В этой статье мы рассмотрим одну из наиболее важных и наименее обсуждаемых функций Laravel web framework — обработку исключений. Laravel поставляется со встроенным обработчиком исключений, который позволяет легко и дружелюбно сообщать об исключениях.
В первой половине статьи мы рассмотрим настройки по умолчанию, предоставляемые обработчиком исключений. Фактически, мы рассмотрим класс Handler, чтобы понять, как Laravel обрабатывает исключения.
Во второй половине статьи мы поговорим о том, как создать пользовательский обработчик исключений, позволяющий обнаруживать пользовательские исключения.
Предварительная настройка
Прежде чем двигаться дальше и сразу погрузиться в класс Handler, давайте посмотрим на пару важных параметров конфигурации, связанных с исключениями.
Откройте файл config/app.php
. Давайте внимательно рассмотрим следующий фрагмент.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
...
...
/*
|--------------------------------------------------------------------------
| Application Debug Mode
|--------------------------------------------------------------------------
|
| When your application is in debug mode, detailed error messages with
| stack traces will be shown on every error that occurs within your
| application. If disabled, a simple generic error page is shown.
|
*/
'debug'
=> env(
'APP_DEBUG'
, false),
...
...
Как следует из названия, если оно установлено в TRUE
, это поможет вам отлаживать ошибки, которые генерируются приложением. Значению по умолчанию этой переменной присваивается значение переменной среды APP_DEBUG
в файле .env
.
В среде разработки вы должны установить значение TRUE
, чтобы вы могли легко отслеживать ошибки и исправлять их. С другой стороны, вы хотите отключить это в рабочей среде, и в этом случае будет отображаться общая страница ошибок.
В дополнение к отображению ошибок, Laravel позволяет регистрировать ошибки в файле журнала. Давайте быстро рассмотрим варианты, доступные для ведения журнала. Опять же, перейдем к файлу config/app.php
и внимательно рассмотрим следующий фрагмент.
1
2
3
4
5
6
7
...
...
'log'
=> env(
'APP_LOG'
,
'single'
),
'log_level'
=> env(
'APP_LOG_LEVEL'
,
'debug'
),
...
...
Поскольку Laravel использует библиотеку Monolog PHP для ведения журнала, вы должны установить вышеуказанные параметры в контексте этой библиотеки.
Файл журнала по умолчанию находится в файле storage/logs/laravel.log
, и в большинстве случаев этого достаточно. С другой стороны, APP_LOG_LEVEL
устанавливается в значение, которое указывает на серьезность ошибок, которые будут регистрироваться.
Таким образом, это было базовое введение в параметры конфигурации, доступные для исключений и ведения логов.
Затем давайте взглянем на класс Handler, который поставляется с приложением Laravel по умолчанию. Откройте файл app/Exceptions/Handler.php
.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
<?php
namespace
App\Exceptions;
use
Exception;
use
Illuminate\Auth\AuthenticationException;
use
Illuminate\Foundation\Exceptions\Handler
as
ExceptionHandler;
class
Handler
extends
ExceptionHandler
{
/**
* A list of the exception types that should not be reported.
*
* @var array
*/
protected
$dontReport
= [
\Illuminate\Auth\AuthenticationException::
class
,
\Illuminate\Auth\Access\AuthorizationException::
class
,
\Symfony\Component\HttpKernel\Exception\HttpException::
class
,
\Illuminate\Database\Eloquent\ModelNotFoundException::
class
,
\Illuminate\Session\TokenMismatchException::
class
,
\Illuminate\Validation\ValidationException::
class
,
];
/**
* Report or log an exception.
*
* This is a great spot to send exceptions to Sentry, Bugsnag, etc.
*
* @param \Exception $exception
* @return void
*/
public
function
report(Exception
$exception
)
{
parent::report(
$exception
);
}
/**
* Render an exception into an HTTP response.
*
* @param \Illuminate\Http\Request $request
* @param \Exception $exception
* @return \Illuminate\Http\Response
*/
public
function
render(
$request
, Exception
$exception
)
{
return
parent::render(
$request
,
$exception
);
}
/**
* Convert an authentication exception into an unauthenticated response.
*
* @param \Illuminate\Http\Request $request
* @param \Illuminate\Auth\AuthenticationException $exception
* @return \Illuminate\Http\Response
*/
protected
function
unauthenticated(
$request
, AuthenticationException
$exception
)
{
if
(
$request
->expectsJson()) {
return
response()->json([
'error'
=>
'Unauthenticated.'
], 401);
}
return
redirect()->guest(route(
'login'
));
}
}
Существуют две важные функции, за которые отвечает класс Handler: сообщение и визуализация всех ошибок.
Давайте внимательно рассмотрим метод report
.
01
02
03
04
05
06
07
08
09
10
11
12
/**
* Report or log an exception.
*
* This is a great spot to send exceptions to Sentry, Bugsnag, etc.
*
* @param \Exception $exception
* @return void
*/
public
function
report(Exception
$exception
)
{
parent::report(
$exception
);
}
Метод report используется для регистрации ошибок в файле логов. В то же время важно также отметить свойство dontReport
, в котором перечислены все типы исключений, которые не должны регистрироваться.
Затем давайте изучим метод render
.
01
02
03
04
05
06
07
08
09
10
11
/**
* Render an exception into an HTTP response.
*
* @param \Illuminate\Http\Request $request
* @param \Exception $exception
* @return \Illuminate\Http\Response
*/
public
function
render(
$request
, Exception
$exception
)
{
return
parent::render(
$request
,
$exception
);
}
Если метод report
используется для регистрации или сообщения об ошибках, метод render
используется для визуализации ошибок на экране. Фактически, этот метод обрабатывает то, что будет отображаться пользователям при возникновении исключения.
Метод render
также позволяет настраивать ответ для разных типов исключений, как мы увидим в следующем разделе.
Наконец, метод unauthenticated
обрабатывает исключение AuthenticationException
, которое позволяет вам определять, что будет отображаться для пользователей, если они не прошли проверку подлинности для доступа к странице, которую они ищут.
Пользовательский класс исключения
В этом разделе мы создадим собственный класс исключений, который обрабатывает исключения типа CustomException
. Идея создания пользовательских классов исключений заключается в том, чтобы легко управлять пользовательскими исключениями и одновременно создавать настраиваемые ответы.
Двигаемся дальше и создаем файл app/Exceptions/CustomException.php
со следующим содержимым.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?php
namespace
App\Exceptions;
use
Exception;
class
CustomException
extends
Exception
{
/**
* Report the exception.
*
* @return void
*/
public
function
report()
{
}
/**
* Render the exception into an HTTP response.
*
* @param \Illuminate\Http\Request
* @return \Illuminate\Http\Response
*/
public
function
render(
$request
)
{
return
response()->view(
'errors.custom'
,
array
(
'exception'
=>
$this
)
);
}
}
Важно отметить, что класс CustomException
должен расширять основной класс Exception
. Для демонстрационных целей мы обсудим только метод render, но, конечно, вы также можете настроить метод report.
Как вы можете видеть, в нашем случае мы перенаправляем пользователей на страницу ошибок error.custom
. Таким образом, вы можете создавать собственные страницы ошибок для определенных типов исключений.
Конечно, нам нужно создать соответствующий файл представления в resources/views/errors/custom.blade.php
.
1
Exception details: <b>{{
$exception
->getMessage() }}</b>
Это довольно простой файл, который отображает сообщение об ошибке, но, конечно же, вы могли бы спроектировать его так, как вы этого хотите.
Нам также необходимо внести изменения в метод render файла app/Exceptions/Handler.php
, чтобы наш пользовательский класс исключений мог быть вызван. Давайте заменим метод render следующим содержимым в файле app/Exceptions/Handler.php
.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
...
...
/**
* Render an exception into an HTTP response.
*
* @param \Illuminate\Http\Request $request
* @param \Exception $exception
* @return \Illuminate\Http\Response
*/
public
function
render(
$request
, Exception
$exception
)
{
if
(
$exception
instanceof
\App\Exceptions\CustomException) {
return
$exception
->render(
$request
);
}
return
parent::render(
$request
,
$exception
);
}
...
...
Как вы можете видеть, сперва мы проверяем тип исключения в методе render. Если тип исключения — \App\Exceptions\CustomException,
мы вызываем метод render этого класса.
Итак, все уже готово. Далее, давайте продолжим и создадим файл контроллера в app/Http/Controllers/ExceptionController.php
, чтобы мы могли протестировать наш собственный класс исключений.
01
02
03
04
05
06
07
08
09
10
11
12
13
<?php
namespace
App\Http\Controllers;
use
App\Http\Controllers\Controller;
class
ExceptionController
extends
Controller
{
public
function
index()
{
// something went wrong and you want to throw CustomException
throw
new
\App\Exceptions\CustomException(
'Something Went Wrong.'
);
}
}
Конечно, вам нужно добавить соответствующий маршрут в routes/web.php
, как показано в следующем фрагменте.
1
2
// Exception routes
Route::get(
'exception/index'
,
'ExceptionController@index'
);
И теперь вы можете открыть http://your-laravel-site.com/exception/index , чтобы узнать, работает ли он так, как ожидалось. Он должен отображать представление errors.custom
в соответствии с нашей конфигурацией.
Таким образом, вы должны обрабатывать пользовательские исключения в Laravel. На этом мы подходим к концу этой статьи — надеюсь, вам понравилось!
Вывод
Сегодня мы изучили функцию обработки исключений в Laravel. В начале статьи мы рассмотрели базовую конфигурацию, предоставленную Laravel, чтобы отображать и сообщать об исключениях. Кроме того, мы кратко рассмотрели класс обработчика исключений по умолчанию.
Во второй половине статьи мы подготовили специальный класс обработчика исключений, который продемонстрировал, как вы можете обрабатывать пользовательские исключения в своем приложении.