How do I get the HTTP Status Code from an Exception thrown in Laravel?

Viewed 17504

I am currently integrating some logic in App/Exceptions/Handler.php. I would like to be able to access the HTTP Status Code on the $exception variable:

public function report(Throwable $exception)
{
    dd($exception->statusCode);
    parent::report($exception);
}

However I get the following error:

ErrorException Undefined property: ErrorException::$statusCode

When I dd($exception) I get the following:

Symfony\Component\HttpKernel\Exception\NotFoundHttpException {#1214 ▼
  -statusCode: 404
  -headers: []
  #message: ""
  #code: 0
  #file: "C:\Users\CEX\Documents\GitHub\unified\vendor\laravel\framework\src\Illuminate\Routing\AbstractRouteCollection.php"
  #line: 43
  trace: {▶}
}

How do I access the statusCode?

3 Answers

If you look at the source code of Symfony\Component\HttpKernel\Exception\NotFoundHttpException you will find that it extends Symfony\Component\HttpKernel\Exception\HttpException if you look at the declaration of the class you will see that $statusCode is private but it has a getter method

class HttpException extends \RuntimeException implements HttpExceptionInterface
{
    private $statusCode;
    private $headers;

    public function __construct(int $statusCode, string $message = null, \Throwable $previous = null, array $headers = [], ?int $code = 0)
    {
        $this->statusCode = $statusCode;
        $this->headers = $headers;

        parent::__construct($message, $code, $previous);
    }

    public function getStatusCode()
    {
        return $this->statusCode;
    }
    //...
}

As such you simply need to do $exception->getStatusCode() to retrieve the status code (404 in your case) though you should do a check to make sure your throwable implements the HttpExceptionInterface because that might not always be the case and so the method would not exist and you would get a fatal error

if ($exception instanceof \Symfony\Component\HttpKernel\Exception\HttpExceptionInterface) {
  $code = $exception->getStatusCode();
}

follow @Tofandel answer, my practice is as follows,
Since this question is relatively new I presume you are suing Laravel version 7 or 8. According to the documentary of Error Handling, the correct page rendering method has now been as

public function render($request, Throwable $exception)
{
    if ($exception instanceof CustomException) {
    return response()->view('errors.custom', [], 500);
    }

    return parent::render($request, $exception);
}

In order to use customised error view, you would have to tell Laravel what kind of Exception instance your thrown $exception is. To overwrite the internal error handling you would want to catch the thrown as a HTTP exception. For these versions the correct Class is as Symfony\Component\HttpKernel\Exception\. Therefore,

  1. bring in the handling Class by
    use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
    on the top of your app\Exceptions\Handler.php

  2. modify the default render() method to something like follows in accordance to your scenario,

use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
    //
    //
public function render($request, Throwable $exception)
{
    // return parent::render($request, $exception);
    if ($exception instanceof HttpExceptionInterface) {
        if (env('APP_ENV') === 'production' && $exception->getStatusCode() == 404) {
            return response()->view('errors.404', [], 404);
        }
        if (env('APP_ENV') === 'production' && $exception->getStatusCode() == 500) {
            return response()->view('errors.500', [], 500);
        }
    }
    return parent::render($request, $exception);
}
Related