Throwing exception within exception handler

2019-04-05 02:50发布

问题:

I have a script with an exception handler. This exception handler cleans up a couple connections, prior to the script exiting after an exception.

I would like to re-throw the exception from this exception handler so that it is handled by PHP's own last-resort exception handler, where the error is written to PHP's error log, or whatever the default is, as configured in PHP.ini.

Unfortunately, this doesn't seem like a possibility, as outlined here:

http://www.php.net/manual/en/function.set-exception-handler.php#68712

Will cause a Fatal error: Exception thrown without a stack frame

Is there another way to bubble the error up the stack so that PHP handles it after my exception handler is done cleaning up?

回答1:

You can not re-throw from the exception handler, however, there are other places you can. For example you can de-couple the re-throw from the handler by encapsulating things into a class of it's own and then use the __destruct() function (PHP 5.3, Demo):

<?php

class ExceptionHandler
{
    private $rethrow;
    public function __construct()
    {
        set_exception_handler(array($this, 'handler'));
    }
    public function handler($exception)
    {
        echo  "cleaning up.\n";
        $this->rethrow = $exception;
    }
    public function __destruct()
    {
        if ($this->rethrow) throw $this->rethrow;
    }
}

$handler = new ExceptionHandler;

throw new Exception();

Put this into my error log:

[29-Oct-2011 xx:32:25] PHP Fatal error: Uncaught exception 'Exception' in /.../test-exception.php:23
Stack trace:
#0 {main}
thrown in /.../test-exception.php on line 23


回答2:

Just catch the exception and log the message yourself, then rethrow.

try {
    $foo->doSomethingToCauseException();
} catch (Exception $e) {
    error_log($e->getMessage());
    throw $e;
}

If you bubble up to the top and PHP is unable to handle, it will result in uncaught exception.



回答3:

Will cause a Fatal error: Exception thrown without a stack frame

This error means that your exception is thrown from a code that is not part of the script (as far as PHP knows). Examples of such code include custom exception handler set with set_exception_handler() and any class destructor method. There's no choice but to NOT throw an exception from such a code.

If you want PHP native error handling, I'd suggest you to call trigger_error() instead. It should log the error if you don't have custom error handler and you use suitable error type. For example, E_USER_ERROR should be fine.



回答4:

Just rethrow the exception as a RunTimeException and it will keep the stacktrace :)

try {
    // bad exception throwing code
} catch (Exception $e) {
    throw new RuntimeException($e->getMessage(), $e->getCode(), $e);
}


回答5:

From http://www.php.net/manual/en/function.set-exception-handler.php#88082 i read: Another solution is to restore the error handler at the beginning of the exception handler. Have you tried it?