13

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?

3
  • 1
    Using a custom exception handler will still trigger a fatal error and thus log the error. Commented Oct 26, 2011 at 2:45
  • Why don't you just throw the exception again from your handler? It works if you know how. And it will triggers PHP last resort handler you're looking for. Commented Oct 30, 2011 at 13:45
  • I've seen this before (and would recommend restoring the error handler) but I can't reproduce right now! Is this issue partial to a version of PHP / .ini settings? Commented Oct 31, 2011 at 9:41

5 Answers 5

18
+50

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
Sign up to request clarification or add additional context in comments.

3 Comments

See as well, which is somewhat related about the __destruct: How to determine that a PHP script is in termination phase?
Thanks @hakre, your solution works. More of a workaround than I was hoping for, but I do understand why this is necessary.
Hey Brad, thanks for the acceptance. I like this "workaround" more than the suggestion on the user-comments on php.net to create the error log entry on ones own. Why re-invent the wheel? I tried also with register shutdown function, but this one here I like better.
8

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.

2 Comments

An uncaught exception would be fine with me. I want to bubble all the up to the top. I am error logging myself right now (using the exact method you are describing), but would rather let PHP handle it, for consistency.
I see. I'm curious about this as well. In my experience the only way PHP handles exceptions is by causing the page to explode, lol.
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.

3 Comments

Or just throw the exception again which depending on configuration will give the proper backtrace.
hakre: just try it (throw anything from inside a custom exception handler or class destructor method) -- you'll find that it does not work. It does not matter if you use xdebug or not.
Mikko, looks like my answer requires PHP 5.3. See as well codepad.viper-7.com/jamrqP
2

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);
}

Comments

0

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?

1 Comment

This doesn't work, sorry. The restore_exception_handler() has no effect within an exception.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.