Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Catch ErrorException that wraps a fatal PHP error

In my homemade PHP MVC framework, I've written a little error handler that wraps PHP errors in an exception, then throws it.

class ErrorController extends ControllerAbstract {

    ...

    public static function createErrorException($number, $message = NULL, $file = NULL, $line = NULL, array $context = array()) {
        throw new ErrorException($message, $number, 0, $file, $line);
    }
}

Which is then registered using set_error_handler(). This works fine, with the exception (no pun intended) of fatal errors. My custom error handler is still called, but I can't catch the ErrorException that is thrown.

An example of such an error would be trying to include a file that doesn't exist:

    try {
        require 'Controller/NonExistentController.php';
    } catch (ErrorException $exc) {
        echo $exc->getTraceAsString(); // code never reaches this block
    }

My custom error handler is called and the exception is thrown, but the code never reaches the "catch" block. Instead, PHP generates HTML (bad!):


Warning: Uncaught exception 'ErrorException' with message 'require(Controller/NonExistentController.php): failed to open stream: ...

Followed by:

Fatal error: Program::main(): Failed opening required 'Controller/NonExistentController.php' (include_path='.:') in ...

I do not want to attempt recovering from a fatal error, but I do want my code to exit gracefully. In this instance, that means sending back an XML or JSON response indicating an internal error, because this is a REST application and that's what my clients expect. HTML responses would most likely break the client applications as well.

Should I go about this differently?

like image 720
Steven Liekens Avatar asked Nov 16 '13 14:11

Steven Liekens


1 Answers

Look at documentation about require on php.net:

require is identical to include except upon failure it will also produce a fatal E_COMPILE_ERROR level error. In other words, it will halt the script whereas include only emits a warning (E_WARNING) which allows the script to continue.

In your case you can handle fatal errors with help of register_shutdown_function, which requires PHP 5.2+:

function customFatalHandler() {
  $error = error_get_last();

  if( $error === NULL) {
      return;
  }

  $type   = $error["type"];
  $file = $error["file"];
  $line = $error["line"];
  $message  = $error["message"];

  echo "Error `$type` in file `$file` on line $line with message `$message`"; 
}

register_shutdown_function("customFatalHandler");

Also this can be helpfull for you

  1. error_get_last() and custom error handler
  2. Why doesn't PHP catch a "Class not found" error?
like image 151
Nick Bondarenko Avatar answered Sep 30 '22 06:09

Nick Bondarenko