问题
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?
回答1:
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
- error_get_last() and custom error handler
- Why doesn't PHP catch a "Class not found" error?
回答2:
I'm sorry to have such a negative answer, but you (VERY PROBABLY) can't.
PHP is designed to chug on for as long as it can for some weird reason, you have a typo? silently initialise that variable to null, you put [] after something, evaluate as null if operator makes no sense!
This is extra messy with error handling, there are like 4 systems at play that do not work together. PHP does some error handling by "monkey patching", this causes a problem if you try to handle something in an error handler by throwing, it isn't "unpatched" until the handler exits.
With the shutdown handler, throwing from there can cause huge problems! It bit me on the ass before, I don't want to talk about it :P
It's also implementation defined as to whether files "resources" in PHP speak) are closed when shutting down, it was created to help plugins tidy up on web-servers. (hence you can have a list of them)
来源:https://stackoverflow.com/questions/20019548/catch-errorexception-that-wraps-a-fatal-php-error