restore_exception_handler

Restores the exception handler that was active before the last set_exception_handler() call.

Signature
restore_exception_handler(): true
  • Added in PHP 5.0

Return value

trueAlways returns true.

Changelog

  • PHP 8.3.0The active exception handler is unset while it runs, so calls made from inside a handler see no previously defined handler.
  • PHP 8.3.5Calling it from inside an exception handler re-installs the currently running handler; a second call is needed to install the handler that was active before it.

restore_exception_handler() pops the handler added by the most recent set_exception_handler() call and reactivates the one beneath it, which may be another user handler or PHP's default behaviour of printing an uncaught-exception fatal error.

Stack semantics

Handlers stack in registration order, and each restore removes exactly one. Two set calls followed by one restore leave the first handler in charge — that is the standard way to demonstrate the behaviour and the standard way people get it wrong. Always pair each set with exactly one restore, in a finally block if the code between them can throw.

Calling it from inside a handler

PHP 8.3 changed this corner. The running handler is unset for the duration of its own execution, and as of 8.3.5 it is pushed back onto the stack when it returns unless the handler modified the stack itself. The practical consequence: calling restore_exception_handler() once from inside a handler re-installs the handler that is currently running, not the one before it. You need a second call to reach the previous handler. Unless you are deliberately manipulating the stack mid-handling, do not call it from inside a handler at all.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Remove a test harness's exception handler in tearDown so later tests see the real one
  • Restore the application's crash reporter after a script temporarily replaced it
  • Unwind handlers installed by a plugin that is being deactivated at runtime

Frequently asked questions

Why does restore_exception_handler not restore the default handler?

Because handlers form a stack and each call pops only one level. If you called set_exception_handler() twice, the first restore just reinstates the earlier handler; call it once per set.

Can I call restore_exception_handler inside an exception handler?

You can, but since PHP 8.3.5 the first call re-installs the handler that is currently running, so you need a second call to reach the one before it. Avoid it unless you are intentionally rewriting the stack.

Does restore_exception_handler return false on failure?

No, it always returns true, even when no handler was ever set. Use get_exception_handler() on PHP 8.5 to check what is actually installed.

More examples

Back to PHP's default behaviour

After the restore, get_exception_handler() reports NULL, meaning uncaught exceptions would again produce PHP's standard fatal error. The try/catch at the end still works, since handlers only ever see exceptions nothing caught.

Example · php
<?php
set_exception_handler(fn(Throwable $e) => print("custom: {$e->getMessage()}\n"));
var_dump(get_exception_handler() !== null);   // bool(true)

var_dump(restore_exception_handler());        // bool(true)
var_dump(get_exception_handler());            // NULL

try { throw new LogicException('now caught normally'); }
catch (LogicException $e) { echo 'caught: ', $e->getMessage(), "\n"; }

Restoring safely around risky work

The finally block guarantees the pop happens whether the callback returns or throws. Leaving a temporary handler installed is the usual cause of a later crash being swallowed by code that has nothing to do with it.

Example · php
<?php
function withReporter(callable $fn): void {
    set_exception_handler(fn(Throwable $e) => print("reported: {$e->getMessage()}\n"));
    try {
        $fn();
    } finally {
        restore_exception_handler();
    }
}

withReporter(function () { echo "work done\n"; });
var_dump(get_exception_handler());   // NULL - handler removed cleanly

Two sets, two restores

The first restore leaves handler A in place, which is why a single restore after two sets does not return you to the default. Only the second call empties the stack.

Example · php
<?php
set_exception_handler(fn(Throwable $e) => print("A\n"));
set_exception_handler(fn(Throwable $e) => print("B\n"));

restore_exception_handler();
var_dump(get_exception_handler() !== null);   // bool(true) - A is active

restore_exception_handler();
var_dump(get_exception_handler());            // NULL - stack empty

Discussion

  • Be the first to comment on this lesson.