Обработка исключений в Laravel: советы и рекомендации

Источник: «Handling Exceptions in laravel: Tips and Tricks»
Laravel — это популярный фреймворк, который обеспечивает простой и элегантный способ создания веб-приложений. Одной из особенностей, которая выделяет Laravel, является встроенная система обработки ошибок и исключений. В этой статье мы рассмотрим некоторые советы и рекомендации по эффективной обработке исключений в 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 — одна из самых мощных функций, которая делает разработку веб-приложений проще и приятнее. Освоив эту систему, вы сможете создавать надёжные и удобные для пользователя приложения, способные корректно справляться с любыми непредвиденными ситуациями.

Дополнительные материалы

Предыдущая Статья

Новое в Symfony 6.3 — Улучшения DX (Часть 3)

Следующая Статья

Тригоно­метриче­ские функции в CSS