Обработка исключений в Laravel: советы и рекомендации
Что такое исключения в Laravel
Исключения — это ошибки, возникающие во время выполнения программы и нарушающие нормальный поток управления. Например, попытка доступа к несуществующему свойству объекта, деление на ноль или вызов функции с недопустимыми аргументами — это всё примеры исключений.
Исключения могут создавать сами механизмы PHP (например, ParseError
или TypeError
) или кодом приложения (например, InvalidArgumentException
или ModelNotFoundException
). Исключение также могут быть определены пользователем путём расширения базового класса Exception
или любого из его подклассов.
Как Laravel обрабатывает исключения
Когда вы начинаете новый проект Laravel, обработка ошибок и исключений уже настроена для вас. В классе App\Exceptions\Handler
все исключения, создаваемые вашим приложением, регистрируются, а затем отображаются для пользователя. В этой статье мы углубимся в этот класс.
По умолчанию Laravel преобразует все исключения в HTTP ответы с соответствующими кодами состояния и сообщениями об ошибках. Например, исключение 404 Not Found
приведёт к HTTP-ответу с кодом состояния 404 и сообщением Not Found
. Исключение 500 Internal Server Error
приведёт к HTTP-ответу с кодом состояния 500 и сообщением Whoops, something went wrong
.
Laravel также предоставляет удобный способ отображения пользовательских страниц ошибок для разных кодов состояния HTTP. Например, вы можете создать файл resources/views/errors/404.blade.php
, чтобы настроить страницу ошибки 404. Вы можете использовать любые функции шаблона Blade на своих страницах ошибок, такие как макеты, компоненты и хелперы.
Как выбрасывать исключения в Laravel
Иногда вам может потребоваться генерировать/выбросить исключение вручную в коде приложения, чтобы указать, что что-то пошло не так или что какое-то условие не было выполнено. Например, вы можете создать исключение, если пользователь попытается получить права доступа к ресурсу, на просмотр которого у него нет прав.
Чтобы выбросить исключение в Laravel, вы можете использовать ключевое слово throw
, за которым следует экземпляр класса исключения. Например:
public function show($id)
{
$post = Post::find($id);
if ($post == null) {
// Выбросить исключение, если статья не существует
throw new ModelNotFoundException('Post not found');
}
if (Auth::user()->cannot('view', $post)) {
// Выбросить исключение, если пользователь не авторизован для просмотра статьи
throw new AuthorizationException('You are not allowed to view this post');
}
return view('posts.show', compact('post'));
}
Вы также можете использовать хелпер abort()
для выбрасывания исключения, чтобы создать исключение с заданным кодом HTTP состояния и дополнительным сообщением. Например:
public function update(Request $request, $id)
{
$post = Post::find($id);
if ($post == null) {
// Прервать с кодом состояния 404 и пользовательским сообщением
abort(404, 'Post not found');
}
if (Auth::user()->cannot('update', $post)) {
// Прервать с кодом состояния 403 и сообщением по умолчанию
abort(403);
}
// Обновить статью ...
}
Как перехватывать исключения в Laravel
Вам может понадобиться перехватить исключение и обработать его иначе, чем это делает поведение по умолчанию. Например, вы можете захотеть вывести в лог дополнительную информацию, выполнить некие действия по очистке или перенаправить пользователя на другую страницу.
Чтобы перехватить исключения в Laravel, вы можете использовать блоки try-catch-finally
. Блок try
содержит код, который может вызвать исключение. Блок catch
содержит код, который будет выполняться, если возникнет исключение. Блок finally
содержит код, который всегда будет выполняться независимо от того, выброшено исключение или нет. Например:
try {
// Пробуем списать деньги с кредитной карты пользователя ...
} catch (PaymentFailedException $e) {
// Ловим и обрабатываем исключение сбоя платежа ...
} finally {
// Всегда высвобождайте ресурсы ...
}
Как настроить обработку исключений в Laravel
Laravel предоставляет мощный и гибкий способ настроить обработку исключений в вашем приложении. Класс App\Exceptions\Handler
— центральное место, где вы можете зарегистрировать собственную логику обработки исключений.
Класс Handler
имеет два метода: report
и render
. Метод report
отвечает за регистрацию исключения или отправку его во внешний сервис, например Bugsnag
or Sentry
. Метод render
отвечает за преобразование исключения в HTTP-ответ, который будет отправлен обратно пользователю.
Вы можете переопределить эти методы в своём классе Handler
, чтобы настроить их поведение. Например, вы можете добавить некую дополнительную логику в метод report
, чтобы сохранять в лог дополнительную информацию или отправлять уведомление по электронной почте:
public function report(Throwable $exception)
{
// Вызов родительского метода report
parent::report($exception);
// Добавьте немного пользовательской логики
if ($exception instanceof PaymentFailedException) {
// Сохраняем в лог дополнительную информацию
Log::info('Payment failed for user ' . Auth::id());
// Отправляем уведомление по e-mail
Mail::to(Auth::user())->send(new PaymentFailedNotification($exception));
}
}
Также вы можете изменить метод render
, чтобы изменить способ отображения исключения для пользователя. Например, вы можете вернуть пользовательский JSON-ответ для API запросов:
public function render($request, Throwable $exception)
{
// Если request ожидает JSON
if ($request->expectsJson()) {
// Возвращаем пользовательский JSON-ответ
return response()->json([
'error' => $exception->getMessage(),
'code' => $exception->getCode(),
], $exception->getStatusCode());
}
// В противном случае, вызываем родительский метод render
return parent::render($request, $exception);
}
Как зарегистрировать пользовательские обработчики исключений в Laravel
Другой способ настроить обработку исключений в Laravel — зарегистрировать пользовательские обработчики исключений с помощью метода register
класса Handler
. Этот метод позволяет определить замыкание, которое будет выполняться при возникновении исключений определённого типа.
Например, вы можете зарегистрировать собственный обработчик для ValidationException
, который будет перенаправлять пользователя обратно на предыдущую страницу с ошибками валидации:
public function register()
{
// Регистрируем пользовательский обработчик для ValidationException
$this->renderable(function (ValidationException $e, $request) {
// Если request ожидает JSON
if ($request->expectsJson()) {
// Возвращаем JSON-ответ с ошибками валидации
return response()->json($e->errors(), $e->status);
}
// В противном случае, перенаправляем обратно с ошибками валидации
return redirect()->back()->withInput()->withErrors($e->errors());
});
}
Вы также можете зарегистрировать несколько обработчиков для разных типов исключений. Например, вы можете зарегистрировать собственный обработчик для ModelNotFoundException
, который будет возвращать ответ 404 с пользовательским сообщением:
public function register()
{
// Регистрируем пользовательский обработчик для ModelNotFoundException
$this->renderable(function (ModelNotFoundException $e, $request) {
// Возвращаем ответ 404 с пользовательским сообщением
return response()->view('errors.model', [
'message' => 'The requested model was not found',
], 404);
});
}
Заключение
В этой статье мы узнали несколько советов и приёмов, как эффективно обрабатывать исключения в Laravel. Мы увидели, как создавать и перехватывать исключения вручную, как настраивать обработку исключений с помощью класса Handler
и как регистрировать пользовательские обработчики исключений.
Система обработки ошибок и исключений Laravel — одна из самых мощных функций, которая делает разработку веб-приложений проще и приятнее. Освоив эту систему, вы сможете создавать надёжные и удобные для пользователя приложения, способные корректно справляться с любыми непредвиденными ситуациями.