Best way to handle register_shutdown_function


#1

Hello there.
I’m trying to write a piece of code to best handle extreme-cases where my API runs out of memory handling a request in PHP 7 using the Slim 3 framework. At the moment I have the following snippet at the very start of my application before Slim is even used/started/initialized.

$fatal_error_callback = function() use ($logger) {
    $error = error_get_last();
    
    if (!empty($error))
    {
        # ... more code for loggging the issue ...
        
        # return a message to the user.
        header('Content-Type: application/json');
        header('Status', 'Error');
        http_response_code(500);
        
        $responseData = array(
            'result' => 'error',
            'message' => 'Request was too large, please find an alternative.',
        );
        
        die(json_encode($responseData, JSON_UNESCAPED_SLASHES));
    }
};

register_shutdown_function($fatal_error_callback);

I would like to be able to get access to the slim request object from within this handler if it exists, so that I can get access to information about the request the user was trying to make. This way I could suggest alternative ways the user could get the information they want over multiple requests. I have a singleton for being able to get the slim app object that was being used, but I understand that either you cant get the request from this, or that getting it would be pointless.

My current plan is to add a new piece of middleware that executes before the request is handled, that registers details of the request, such as the route-name, into an area that can be globally accessed, such a singleton, static method, or global variable, which I could then access from the shutdown handler, but was wondering if there was a better way that was more “slim like”.


#2

You can use the built in functions for handle errors in Slim.

You can use this one and check the doc for other use cases.


#3

I have already registered the slim error handlers (below) but they don’t seem to catch when you run out of memory (fatal error), which is why I have a registered shutdown function. Perhaps there is some issue with how I have registerd them.

        $app = SiteSpecific::getSlimApp();
        
        // set the error handlers
        // https://www.slimframework.com/docs/handlers/error.html
        $container = $app->getContainer();
        
        $errorHandler = function($request, $response, $args) {
            return $response->withStatus(500)
                            ->withHeader('Content-Type', 'application/json')
                            ->write('Something went wrong!');
        };
        
        
        // This is returned when the route exists but the method, such as POST or PATCH does
        // not exist for it.
        $methodNotAllowedHandler = function($request, $response, $args) {
            $ex = new Exception("That method is not allowed.", HTTP_METHOD_NOT_ALLOWED);
            return SiteSpecific::getErrorResponseForException($ex, $response);
        };
        
        $container['errorHandler'] = function ($container) use ($errorHandler) {
            return $errorHandler;
        };
        
        // Runtime PHP errors (PHP 7+ only)
        $container['phpErrorHandler'] = function ($container) use ($errorHandler) {
            return $errorHandler;
        };
        
        $container['notAllowedHandler'] = function ($container) use ($methodNotAllowedHandler) {
            return $methodNotAllowedHandler;
        };
        
        $container['notFoundHandler'] = function ($container) {
            // need to use an annonymous class here due to the fact that need to use $container
            // at last possible second.
            return new class($container) {
                private $m_container;
                
                public function __construct($container)
                {
                    $this->m_container = $container;
                }
                
                public function __invoke($request, $response) 
                {
                    $ex = new Exception("That method/route does not exist.", HTTP_NOT_FOUND);
                    return SiteSpecific::getErrorResponseForException($ex, $response);
                }
            };
        };

#4

Which versino of Slim are you using?
In PHP7 all errors that implements Throwable can be caught.
I recommend you to se BooBoo package if you’re having trouble with it.

You can see an example of implementation here:
Register in the container
Call it before running the app