Документация Laravel 10.x
Здесь ты найдешь сниппеты по Laravel и полезные советы по веб-разработке.
Когда вы создаете новый проект 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; /** * Регистрация обратных вызовов обработки исключений для приложения. */public function register(): void{ $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<string, mixed> */protected function context(): array{ return array_merge(parent::context(), [ 'foo' => 'bar', ]);}
Хотя добавление контекста к каждому сообщению журнала может быть полезным, иногда у определенного исключения может быть уникальный контекст, который вы хотели бы включить в ваши логи. Определив метод context
в одном из исключений вашего приложения, вы можете указать любые данные, относящиеся к этому исключению, которые следует добавить в запись лога исключения:
<?php namespace App\Exceptions; use Exception; class InvalidOrderException extends Exception{ // ... /** * Получение контекстной информации об исключении. * * @return array<string, mixed> */ public function context(): array { return ['order_id' => $this->orderId]; }}
report
Иногда вам может потребоваться сообщить об исключении, но продолжить обработку текущего запроса. Функция-помощник report
позволяет вам быстро сообщить об исключении через обработчик исключений, не рендеря страницу ошибки для пользователя:
public function isValid(string $value): bool{ try { // Проверка значения... } catch (Throwable $e) { report($e); return false; }}
Если вы используете функцию report
во всем вашем приложении, иногда может возникнуть необходимость сообщить об одном и том же исключении несколько раз, создавая дублирующие записи в ваших журналах.
Если вы хотите гарантировать, что один экземпляр исключения будет сообщен только один раз, вы можете установить свойство $withoutDuplicates
в true
в классе обработчика исключений вашего приложения App\Exceptions\Handler
:
namespace App\Exceptions; use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; class Handler extends ExceptionHandler{ /** * Указывает, что экземпляр исключения должен быть сообщен только один раз. * * @var bool */ protected $withoutDuplicates = true; // ...}
Теперь, когда функция-помощник report
вызывается с тем же экземпляром исключения, будет сообщено только при первом вызове:
$original = new RuntimeException('Whoops!'); report($original); // reported try { throw $original;} catch (Throwable $caught) { report($caught); // ignored} report($original); // ignoredreport($caught); // ignored
Когда сообщения записываются в журналы вашего приложения, они записываются с указанным уровнем журнала, который указывает на серьезность или важность сообщения, регистрируемого.
Как отмечено выше, даже если вы зарегистрируете обратный вызов обработки исключений с использованием метода reportable
, Laravel все равно будет регистрировать исключение с использованием конфигурации журналирования по умолчанию для приложения; однако, поскольку уровень журнала иногда может влиять на каналы, на которые регистрируется сообщение, вы можете желать настроить уровень журнала, с которым определенные исключения регистрируются.
Для этого вы можете определить свойство $levels
в обработчике исключений вашего приложения. Это свойство должно содержать массив типов исключений и соответствующих уровней журнала:
use PDOException;use Psr\Log\LogLevel; /** * Список типов исключений с соответствующими им уровнями журнала. * * @var array<class-string<\Throwable>, \Psr\Log\LogLevel::*> */protected $levels = [ PDOException::class => LogLevel::CRITICAL,];
При построении вашего приложения могут быть типы исключений, о которых вы никогда не хотите сообщать. Чтобы игнорировать эти исключения, определите свойство $dontReport
в обработчике исключений вашего приложения. Все классы, добавленные в это свойство, никогда не будут сообщаться; однако они все равно могут иметь собственную логику отображения:
use App\Exceptions\InvalidOrderException; /** * Список типов исключений, которые не следует сообщать. * * @var array<int, class-string<\Throwable>> */protected $dontReport = [ InvalidOrderException::class,];
Внутренне Laravel уже игнорирует некоторые типы ошибок для вас, такие как исключения, возникающие из 404 HTTP-ошибок или 419 HTTP-ответов, генерируемых недействительными токенами CSRF. Если вы хотите указать Laravel прекратить игнорирование определенного типа исключения, вы можете вызвать метод stopIgnoring
в методе register
вашего обработчика исключений:
use Symfony\Component\HttpKernel\Exception\HttpException; /** * Регистрация обратных вызовов обработки исключений для приложения. */public function register(): void{ $this->stopIgnoring(HttpException::class); // ...}
По умолчанию обработчик исключений Laravel преобразует исключения в HTTP-ответ для вас. Однако вы можете зарегистрировать собственное замыкание отображения для исключений определенного типа. Вы можете сделать это, вызвав метод renderable
в вашем обработчике исключений.
Замыкание, переданное методу renderable
, должно возвращать экземпляр Illuminate\Http\Response
, который может быть создан с помощью вспомогательной функции response
. Laravel определит, какой тип исключения отображает замыкание, изучив тип-подсказку замыкания:
use App\Exceptions\InvalidOrderException;use Illuminate\Http\Request; /** * Регистрация обратных вызовов обработки исключений для приложения. */public function register(): void{ $this->renderable(function (InvalidOrderException $e, Request $request) { return response()->view('errors.invalid-order', [], 500); });}
Вы также можете использовать метод renderable
для замены поведения отображения для встроенных исключений Laravel или Symfony, таких как NotFoundHttpException
. Если замыкание, переданное методу renderable
, не возвращает значения, будет использовано стандартное отображение исключения Laravel:
use Illuminate\Http\Request;use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * Регистрация обратных вызовов обработки исключений для приложения. */public function register(): void{ $this->renderable(function (NotFoundHttpException $e, Request $request) { if ($request->is('api/*')) { return response()->json([ 'message' => 'Record not found.' ], 404); } });}
Вместо определения пользовательского поведения отчетности и отображения в методе register
обработчика исключений вы можете определить методы report
и render
непосредственно в собственных исключениях вашего приложения. Когда эти методы существуют, они автоматически вызываются фреймворком:
<?php namespace App\Exceptions; use Exception;use Illuminate\Http\Request;use Illuminate\Http\Response; class InvalidOrderException extends Exception{ /** * Сообщение об исключении. */ public function report(): void { // ... } /** * Преобразование исключения в HTTP-ответ. */ public function render(Request $request): Response { return response(/* ... */); }}
Если ваше исключение расширяет исключение, которое уже можно отобразить, такое как встроенное исключение Laravel или Symfony, вы можете вернуть false
из метода render
исключения, чтобы отобразить стандартный HTTP-ответ исключения:
/** * Преобразование исключения в HTTP-ответ. */public function render(Request $request): Response|bool{ if (/** Determine if the exception needs custom rendering */) { return response(/* ... */); } return false;}
Если ваше исключение содержит собственную логику отчетности, которая необходима только при выполнении определенных условий, вам может потребоваться инструктировать Laravel иногда сообщать об исключении с использованием конфигурации обработки исключений по умолчанию. Для этого вы можете вернуть false
из метода report
исключения:
/** * Сообщение об исключении. */public function report(): bool{ if (/** Determine if the exception needs custom reporting */) { // ... return true; } return false;}
Примечание Вы можете указать зависимости, необходимые для метода
report
, и они будут автоматически внедрены в метод контейнера служб Laravel.
Если ваше приложение сообщает очень большое количество исключений, вам может потребоваться регулировать, сколько исключений фактически регистрируется или отправляется во внешнюю службу отслеживания ошибок вашего приложения.
Чтобы взять случайную выборку исключений, вы можете вернуть экземпляр Lottery
из метода throttle
обработчика исключений. Если в вашем классе App\Exceptions\Handler
нет этого метода, вы можете просто добавить его в класс:
use Illuminate\Support\Lottery;use Throwable; /** * Ограничение поступающих исключений. */protected function throttle(Throwable $e): mixed{ return Lottery::odds(1, 1000);}
Также возможно условно отбирать выборки по типу исключения. Если вы хотите выборочно обрабатывать только экземпляры определенного класса исключения, вы можете вернуть экземпляр Lottery
только для этого класса:
use App\Exceptions\ApiMonitoringException;use Illuminate\Support\Lottery;use Throwable; /** * Ограничение поступающих исключений. */protected function throttle(Throwable $e): mixed{ if ($e instanceof ApiMonitoringException) { return Lottery::odds(1, 1000); }}
Вы также можете ограничить частоту исключений, регистрируемых или отправляемых на внешний сервис отслеживания ошибок, вернув вместо Lottery
экземпляр Limit
. Это полезно, если вы хотите защититься от внезапных всплесков исключений, затопляющих ваши логи, например, когда сторонний сервис, используемый вашим приложением, недоступен:
use Illuminate\Broadcasting\BroadcastException;use Illuminate\Cache\RateLimiting\Limit;use Throwable; /** * Ограничение поступающих исключений. */protected function throttle(Throwable $e): mixed{ if ($e instanceof BroadcastException) { return Limit::perMinute(300); }}
По умолчанию лимиты будут использовать класс исключения в качестве ключа ограничения частоты. Вы можете настроить это, указав свой собственный ключ, используя метод by
на Limit
:
use Illuminate\Broadcasting\BroadcastException;use Illuminate\Cache\RateLimiting\Limit;use Throwable; /** * Ограничение поступающих исключений. */protected function throttle(Throwable $e): mixed{ if ($e instanceof BroadcastException) { return Limit::perMinute(300)->by($e->getMessage()); }}
Конечно, вы можете возвращать смешанные экземпляры Lottery
и Limit
для разных исключений:
use App\Exceptions\ApiMonitoringException;use Illuminate\Broadcasting\BroadcastException;use Illuminate\Cache\RateLimiting\Limit;use Illuminate\Support\Lottery;use Throwable; /** * Ограничение поступающих исключений. */protected function throttle(Throwable $e): mixed{ return match (true) { $e instanceof BroadcastException => Limit::perMinute(300), $e instanceof ApiMonitoringException => Lottery::odds(1, 1000), default => Limit::none(), };}
Некоторые исключения описывают коды состояния HTTP с сервера. Например, это может быть ошибка "страница не найдена" (404), "ошибка неавторизованного доступа" (401) или даже сгенерированная разработчиком ошибка 500. Чтобы сгенерировать такой ответ отовсюду в вашем приложении, вы можете использовать вспомогательную функцию abort
:
abort(404);
Laravel упрощает отображение пользовательских страниц ошибок для различных кодов состояния HTTP. Например, чтобы настроить страницу ошибки для кодов состояния HTTP 404, создайте шаблон представления resources/views/errors/404.blade.php
. Этот вид будет визуализироваться для всех ошибок 404, сгенерированных вашим приложением. Представления в этом каталоге должны быть названы с учетом кода состояния HTTP, к которому они относятся. Экземпляр исключения Symfony\Component\HttpKernel\Exception\HttpException
, вызванный функцией abort
, будет передан представлению как переменная $exception
:
<h2>{{ $exception->getMessage() }}</h2>
Вы можете опубликовать шаблоны страниц ошибок Laravel по умолчанию с помощью команды Artisan vendor:publish
. После публикации вы можете настроить их по своему усмотрению:
php artisan vendor:publish --tag=laravel-errors
Вы также можете определить "запасную" страницу ошибки для определенной серии кодов состояния HTTP. Эта страница будет визуализироваться, если нет соответствующей страницы для конкретного кода состояния HTTP, который произошел. Для этого определите шаблон 4xx.blade.php
и шаблон 5xx.blade.php
в каталоге resources/views/errors
вашего приложения.