Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

jlrdw's avatar
Level 75

PHP error and exception handling

I see in laravel 7 a change from:

    public function report(Exception $exception)
    {
        parent::report($exception);
    }

To

    public function report(Throwable $exception)
    {
        parent::report($exception);
    }

But php still has:

  • set-exception-handler
  • set-error-handler

An example in a custom framework:

    set_exception_handler('Mini\Core\Logger::ExceptionHandler');
    set_error_handler('Mini\Core\Logger::ErrorHandler');

And in the class:

    /**
     * Saved the exception and calls customer error function.
     *
     * @param  exeption $e
     */
    public static function exceptionHandler($e)
    {
        self::newMessage($e);
    }

Which works well in php including php 7.4.

But if I wanted to do this:

    public static function exceptionHandler(Throwable $e)
    {
        self::newMessage($e);
    }
  • Does that replace both error and exception handling?
  • How do I set it?

Would I still use

    set_exception_handler('Mini\Core\Logger::ExceptionHandler');
    set_error_handler('Mini\Core\Logger::ErrorHandler');

And would the error part be unnecessary:

    public static function errorHandler($number, $message, $file, $line)
    {
        $msg = "$message in $file on line $line";

        if (($number !== E_NOTICE) && ($number < 2048)) {
            self::errorMessage($msg);
            self::$error = $msg;
            self::customErrorMsg();
        }

        return 0;
    }

The php manuel states that:

Both Error and Exception implements the Throwable interface.

So the existing Exception and Error handling already implement throwable. Yet Symfony and Laravel made the change. But only as of laravel 7.

Any help understanding I'll be thankful.

0 likes
6 replies
jlrdw's avatar
Level 75

Well in the custom framework, both of these work:

        if ($e instanceof Exception) {
            self::newMessage($e);
        }
        if ($e instanceof Throwable) {
            self::newThrowMessage($e);  // messages if throwable
        }

But the top one always works first, I think since Exception implements the Throwable interface, and that's direct from the php manual, I can just use the top block of code.

I commented one out then the other, both work the same.

Edit:

Tried two more things:

1

    public static function exceptionHandler($e)
    {
        if (!$e instanceof Exception || !$e instanceof Throwable) {
            self::newMessage('Exception occured');
        }
        if ($e instanceof Throwable) {
            self::newThrowMessage($e);
        } elseif ($e instanceof Exception) {
            self::newMessage($e);
        } else {
            self::newMessage('Whoops');
        }
        
    }

The Throwable gets called.

And since I am using instanceof I need at top:

use Throwable;
use Exception;

2 then tried:

    public static function exceptionHandler($e)
    {
       self::newMessage($e);
    }

No "use" statement needed.

This also works.

So I still don't understand the using of Throwable in laravel now, when both error and exception already implement the Throwable interface. PHP itself takes care of it.

But any thoughts on setting up custom error and exception handlers in php 7.4 will be appreciated.

jlrdw's avatar
Level 75

@rodrigo.pedra thanks for that reply, and yes I've read that PR.

And in my custom handling both errors and exceptions, I have retested throwing multiple types of errors and exceptions at it, and they seem to work fine in PHP, including PHP 7.4.

Bottom line, when throwable is already extended by exception and error, I'm still confused on why symfony had to do that.

I believe they are targeting only a certain type of error, which could be caught as a catch all if they wanted.

I imagine they wanted it to be specific.

I even had an issue

https://github.com/laravel/framework/issues/31673

But laravel uses symfony components.

rodrigo.pedra's avatar

I found some explanation here:

https://www.php.net/manual/en/language.errors.php7.php

The interesting parts are:

1 -

Using catch(\Throwable $e) in a try...catch block can catch both Errors and Exceptions, which wasn't possible before in a single catch block.

I guess (just guess, his wording was very terse) that is what Graham meant in his comment on the issue you linked:

https://github.com/laravel/framework/issues/31673#issuecomment-593292875

2 -

Per what is stated on the link at the top, Errors are now caught by set_exception_handler

As with normal exceptions, these Error exceptions will bubble up until they reach the first matching catch block. If there are no matching blocks, then any default exception handler installed with set_exception_handler() will be called...

Which wasn't the behavior before (so both set_exception_handler and set_error_handler were needed)

So my understanding is that using Throwable allows a more generic approach on error/exception handling.

jlrdw's avatar
Level 75

@rodrigo.pedra what I am basically trying to figure out now is if I do the following:

    public static function exceptionHandler(Throwable $e)
    {
        self::newMessage($e);
    }

Would that work for both errors and exceptions.

And how the setting would have to be changed

set_exception_handler('Mini\Core\Logger::ExceptionHandler');
    set_error_handler('Mini\Core\Logger::ErrorHandler');

In other words leave out set_error_handler, or would that still be needed.

I cannot find a good definitive guide on setting up this stuff in modern PHP 7.4.

The PHP manual still has a reference to both of these.

But my current error and exception Handler does work. Yet I wouldn't mind bringing it more up to date.

jlrdw's avatar
Level 75

After some digging, I finally see how Taylor is doing this:

https://github.com/laravel/framework/blob/7.x/src/Illuminate/Foundation/Bootstrap/HandleExceptions.php#L66

All I had to do is change my exception handler to:

    public static function exceptionHandler(Throwable $e)
    {
        self::newThrowMessage($e);
    }

And change the error handler to:

    public static function errorHandler($severity, $message, $file, $line)
    {
        if (!(error_reporting() & $severity)) {
            // This error code is not included in error_reporting
            return;
        }
        throw new ErrorException($message, 0, $severity, $file, $line);
    }

An example from the php docs. But the original error handler will still work, but I decided to change it to keep the custom framework up to date.

So if anyone is dealing with custom code or framework, study the github link above.

In earlier versions of laravel he had Exception instead of Throwable.

Both still work, just had to do this because Symfony changes. I just didn't understand the changes at first.

But that function from the php manual solved every thing. https://www.php.net/manual/en/class.errorexception.php

Please or to participate in this conversation.