Поддержите проект сделав пожертвование.
Ищете работу? Мы поможем!
Ищете работу? Мы поможем!

Обработка ошибок (Exception)

Вы просматриваете документ для прошлой версии.
Рассмотрите возможность обновления вашего проекта до актуальной версии 10.x. Почему это важно?

Введение

Когда вы запускаете новый проект Laravel, обработка ошибок и исключений уже настроена для вас. Класс App\Exceptions\Handler – это то место, где все исключения, созданные вашим приложением, регистрируются и затем отображаются пользователю. В этой документации мы углубимся в этот класс.

Конфигурирование

Параметр debug в конфигурационном файле config/app.php определяет, сколько информации об ошибке фактически отобразится пользователю. По умолчанию этот параметр установлен, чтобы учесть значение переменной окружения APP_DEBUG, которая содержится в вашем файле .env.

Во время локальной разработки вы должны установить для переменной окружения APP_DEBUG значение true. Во время эксплуатации приложения это значение всегда должно быть false. Если в рабочем окружении будет установлено значение true, вы рискуете раскрыть конфиденциальные значения конфигурации конечным пользователям вашего приложения.

Обработчик исключений

Отчет об исключениях

Все исключения обрабатываются классом App\Exceptions\Handler. Этот класс содержит метод register, в котором вы можете зарегистрировать свои отчеты об исключениях и замыкания рендеринга. Мы подробно рассмотрим каждую из этих концепций. Отчеты об исключениях используются для регистрации исключений или отправки их во внешнюю службу, например Flare, Bugsnag или Sentry. По умолчанию исключения будут регистрироваться в соответствии с вашей конфигурацией логирования. Однако вы можете регистрировать исключения как хотите.

Например, если вам нужно сообщать о различных типах исключений по-разному, вы можете использовать метод reportable для регистрации замыкания, которое должно быть выполнено, когда необходимо сообщить об исключении конкретного типа. Laravel определит о каком типе исключения сообщает замыкание с помощью типизации аргументов:

use App\Exceptions\InvalidOrderException;

/**
 * Зарегистрировать замыкания, обрабатывающие исключения приложения.
 *
 * @return void
 */
public function register()
{
    $this->reportable(function (InvalidOrderException $e) {
        //
    });
}

Когда вы регистрируете собственные замыкания для создания отчетов об исключениях, используя метод reportable, Laravel по-прежнему регистрирует исключение, используя конфигурацию логирования по умолчанию для приложения. Если вы хотите остановить распространение исключения в стек журналов по умолчанию, вы можете использовать метод stop при определении замыкания отчета или вернуть false из замыкания:

$this->reportable(function (InvalidOrderException $e) {
    //
})->stop();

$this->reportable(function (InvalidOrderException $e) {
    return false;
});

Чтобы настроить отчет об исключениях для переданного исключения, вы можете рассмотреть возможность использования отчетных исключений.

Глобальное содержимое журнала

Если доступно, Laravel автоматически добавляет идентификатор текущего пользователя в каждое сообщение журнала исключения в качестве контекстных данных. Вы можете определить свои собственные глобальные контекстные данные, переопределив метод context класса App\Exceptions\Handler вашего приложения. Эта информация будет включена в каждое сообщение журнала исключения, написанное вашим приложением:

/**
 * Получить переменные контекста по умолчанию для ведения журнала.
 *
 * @return array
 */
protected function context()
{
    return array_merge(parent::context(), [
        'foo' => 'bar',
    ]);
}

Контекст журнала исключений

Хотя добавление контекста в каждое сообщение журнала может быть полезно, иногда конкретное исключение может иметь уникальный контекст, который вы хотели бы включить в свои журналы. Определив метод context для конкретного исключения вашего приложения, вы можете указать любые данные, относящиеся к этому исключению, которые должны быть добавлены в запись журнала исключения:

<?php

namespace App\Exceptions;

use Exception;

class InvalidOrderException extends Exception
{
    // ...

    /**
     * Получить контекстную информацию исключения.
     *
     * @return array
     */
    public function context()
    {
        return ['order_id' => $this->orderId];
    }
}

Помощник report

По желанию может потребоваться сообщить об исключении, но продолжить обработку текущего запроса. Помощник report позволяет вам быстро сообщить об исключении через обработчик исключений, не отображая страницу с ошибкой для пользователя:

public function isValid($value)
{
    try {
        // Проверка `$value` ...
    } catch (Throwable $e) {
        report($e);

        return false;
    }
}

Игнорирование исключений по типу

При создании приложения будут некоторые типы исключений, которые вы просто хотите игнорировать и никогда не сообщать о них. Обработчик исключений вашего приложения содержит свойство $dontReport, которое инициализируется пустым массивом. Ни о каких классах, добавленных в это свойство, никогда не будет сообщено; однако у них все еще может быть собственная логика отображения:

use App\Exceptions\InvalidOrderException;

/**
 * Список типов исключений, о которых не следует сообщать.
 *
 * @var array
 */
protected $dontReport = [
    InvalidOrderException::class,
];

За кулисами Laravel уже игнорирует для вас некоторые типы ошибок, такие как исключения, возникающие из-за ошибок 404 HTTP «не найдено» или 419 HTTP-ответ, сгенерированный при недопустимом CSRF-токене.

Отображение исключений

По умолчанию обработчик исключений Laravel будет преобразовывать исключения в HTTP-ответ за вас. Однако вы можете зарегистрировать свое замыкание для отображения исключений конкретного типа. Вы можете сделать это с помощью метода renderable обработчика исключений.

Замыкание, переданное методу renderable, должно вернуть экземпляр Illuminate\Http\Response, который может быть сгенерирован с помощью функции response. Laravel определит, какой тип исключения отображает замыкание с помощью типизации аргументов:

use App\Exceptions\InvalidOrderException;

/**
 * Зарегистрировать замыкания, обрабатывающие исключения приложения.
 *
 * @return void
 */
public function register()
{
    $this->renderable(function (InvalidOrderException $e, $request) {
        return response()->view('errors.invalid-order', [], 500);
    });
}

Вы также можете использовать метод renderable чтобы переопределить отображение для встроенных исключений Laravel или Symfony, таких, как NotFoundHttpException. Если замыкание, переданное методу renderable не возвращает значения, будет использоваться отрисовка исключений Laravel по умолчанию:

use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

/**
 * Зарегистрировать замыкания, обрабатывающие исключения приложения.
 *
 * @return void
 */
public function register()
{
    $this->renderable(function (NotFoundHttpException $e, $request) {
        if ($request->is('api/*')) {
            return response()->json([
                'message' => 'Record not found.'
            ], 404);
        }
    });
}

Отчетные и отображаемые исключения

Вместо проверки типов исключений в методе register обработчика исключений вы можете определить методы report и render непосредственно для ваших исключений. Если эти методы существуют, то они будут автоматически вызываться фреймворком:

<?php

namespace App\Exceptions;

use Exception;

class InvalidOrderException extends Exception
{
    /**
     * Отчитаться об исключении.
     *
     * @return bool|null
     */
    public function report()
    {
        //
    }

    /**
     * Преобразовать исключение в HTTP-ответ.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function render($request)
    {
        return response(...);
    }
}

Если ваше исключение расширяет исключение, которое уже доступно для визуализации, например встроенное исключение Laravel или Symfony, вы можете вернуть false из метода render исключения, чтобы отобразить HTTP-ответ исключения по умолчанию:

/**
 * Преобразовать исключение в HTTP-ответ.
 *
 * @param  \Illuminate\Http\Request  $request
 * @return \Illuminate\Http\Response
 */
public function render($request)
{
    // Определить, требуется ли для исключения пользовательское отображение...

    return false;
}

Если ваше исключение содержит пользовательскую логику отчетности, которая необходима только при выполнении определенных условий, то вам может потребоваться указать Laravel когда сообщать об исключении, используя конфигурацию обработки исключений по умолчанию. Для этого вы можете вернуть false из метода report исключения:

/**
 * Сообщить об исключении.
 *
 * @return bool|null
 */
public function report()
{
    // Определить, требуется ли для исключения пользовательская отчетность ...

    return false;
}

Вы можете указать любые требуемые зависимости метода report, и они будут автоматически внедрены в метод контейнером служб Laravel.

Сопоставление исключений по типу

Иногда сторонние библиотеки, используемые вашим приложением, могут генерировать исключения, которые вы хотите сделать доступными для рендеринга, но не можете этого сделать, потому что у вас нет контроля над определениями сторонних исключений.

К счастью, Laravel позволяет вам удобно сопоставлять эти исключения с другими типами исключений, которыми вы управляете в своем приложении. Для этого вызовите метод map из метода register вашего обработчика исключений :

use League\Flysystem\Exception;
use App\Exceptions\FilesystemException;

/**
 * Register the exception handling callbacks for the application.
 *
 * @return void
 */
public function register()
{
    $this->map(Exception::class, FilesystemException::class);
}

Если вы хотите больше контролировать создание целевого исключения, вы можете передать методу map замыкание:

use League\Flysystem\Exception;
use App\Exceptions\FilesystemException;

$this->map(fn (Exception $e) => new FilesystemException($e));

HTTP-исключения

Некоторые исключения описывают коды HTTP-ошибок с сервера. Например, это может быть ошибка «страница не найдена» (404), «неавторизованный доступ» (401) или даже ошибка 500, сгенерированная разработчиком. Чтобы создать такой ответ из любой точки вашего приложения, вы можете использовать глобальный помощник abort:

abort(404);

Пользовательские страницы ошибок HTTP

Laravel позволяет легко отображать пользовательские страницы ошибок для различных кодов состояния HTTP. Например, если вы хотите настроить страницу ошибок для кодов HTTP-состояния 404, создайте файл resources/views/errors/404.blade.php. Это представление будет отображено для всех ошибок 404, сгенерированных вашим приложением. Шаблоны в этом каталоге должны быть названы в соответствии с кодом состояния HTTP, которому они соответствуют. Экземпляр Symfony\Component\HttpKernel\Exception\HttpException, вызванный функцией abort, будет передан в шаблон как переменная $exception:

<h2>{{ $exception->getMessage() }}</h2>

Вы можете опубликовать стандартные шаблоны страниц ошибок Laravel с помощью команды vendor:publish Artisan. После публикации шаблонов вы можете настроить их по своему вкусу:

php artisan vendor:publish --tag=laravel-errors