Why does the PHP set_execption_handler capture an Error object

I'm working with error and exception handles in PHP, and am finding some unexpected behaviour when attempting to call a method that doesn't exist.

Here's the PHP:

<?php
    set_error_handler(function() {
        echo 'error';
    });
    set_exception_handler(function() {
        echo 'exception';
        $args = func_get_args();
        print_r($args);
    });
    $obj = new stdClass;
    $obj->jdhgdfkjh();
    exit(0);

Here's the output:


exceptionArray
(
    [0] => Error Object
        (
            [message:protected] => Call to undefined method stdClass::jdhgdfkjh()
            [string:Error:private] => 
            [code:protected] => 0
            [file:protected] => /var/www/domain.com/index.php
            [line:protected] => 11
            [trace:Error:private] => Array
                (
                )

            [previous:Error:private] => 
        )

)

I don't really care whether it's an error or exception that occurs when trying to call a method that doesn't exist. I'm just confused as to why the exception handler is being called with an error object.

Would love some clarity if anyone has run into this before.

1 answer

  • answered 2020-08-07 16:55 onassar

    Going to do my best to answer my own question. @apokryfos is right: the manual has details on this. I find it a bit confusing that the set_exception_handler is catching not just Exception and Throwable objects, but also Error objects (which are Throwable objects, but not Exception objects).

    I find this confusing because set_error_handler has the word "error" in it, and yet, it's not catching these object-types.

    So, for anyone else who stumbles on this, in newer versions of PHP, you can't expect an Exception object for the set_exception_handler callback. You need to expect a Throwable, and non-linearly, you may also get Error objects which are not received by the set_error_handler.

    To deal with that in my own setup, I have the following set_error_handler to make things a bit cleaner:

    set_error_handler(function($errno, $errstr, $errfile, $errline, $errcontext) {
        $args = array($errstr, $errno, E_ERROR, $errfile, $errline);
        $errorException = new \ErrorException(... $args);
    });
    

    This will then be caught by your set_exception_handler callback.
    Hope this is helpful to others :)