phperror-handling

Why does PHP throw fatal errors and break with HTTP 500 although using try/catch blocks?


In my AWS logs, I have entries like this:

[Wed Feb 06 10:12:22.306730 2019] [php7:error] [pid 28445] [client 172.31.10.7:55646] PHP Fatal error: Uncaught Error: Class 'comet_cache' not found in /var/app/current/project-website-wordpress/wp-content/mu-plugins/comet-cache-ec2-enabler.php:41

Those entries are logged when some certain HTTP 500 request happens.

After checking the code, I have found the following (in Line 41 in the file mentioned):

try {
   comet_cache::clear();
} catch(Exception $e) {
   // if comet cache is not activated, we want to continue anyway
}

This basically makes sense - it seems like the class is not found, but if that were the case, the Exception should be caught in the catch() bloc, and the execution should continue.

Why does PHP crash instead?


Solution

  • You are not catching because you are tring to catch an \Exception, but what's being thrown it's an \Error.

    Considering your error message, I would say you are using PHP >= 7 (you should specificy that, error handling has changed significantly from version 5 to version 7).

    On PHP >= 7, most fatal errors are reported not by raising an error, but by throwing an Error object.

    So your statement could be rewritten like:

    try {
        $a = new ClassNotFindable();
    }
    catch (\Error $e) {
       // do your catching
    }
    

    Furthermore, both Error and Exception classes implement the Throwable interface, so you could catching that directly:

    <?php
    
    try {
        $a = new NotFound();
    }
    catch (\Throwable $t) {
        echo "caught!\n";
    
        echo $t->getMessage(), " at ", $t->getFile(), ":", $t->getLine(), "\n";
    }
    

    You can see it working here.

    This is in no way related to AWS, but simply a PHP thing. If you were using PHP < 7 it would still not be caught, but in that case because common errors are not thrown exceptions.

    If you were using PHP5, to be able to catch an error as an exception you'd need to set-up a custom error handler. The example in the manual seems quite appropriate:

    function exception_error_handler($severidad, $mensaje, $fichero, $línea) {
       if (!(error_reporting() & $severidad)) {
           // Este código de error no está incluido en error_reporting
           return;
       }
       throw new ErrorException($mensaje, 0, $severidad, $fichero, $línea);
    }
    set_error_handler("exception_error_handler");