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

В этой статье мы рассмотрим одну из наиболее важных и наименее обсуждаемых функций 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, чтобы отображать и сообщать об исключениях. Кроме того, мы кратко рассмотрели класс обработчика исключений по умолчанию.

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