Russian (Pусский) translation by Stanislav Protasevich (you can also view the original English article)



Вступление
В сегодняшнем уроке мы покажем как отловить ошибки и исключения в Yii, а также рассмотрим несколько возможных вариантов развития событий.
Не знакомы с Yii? Наверстать упущенное можно, прочитав статью Знакомство с фрэймворком Yii и серию Разработка на базе Yii2.
В чём разница между ошибками и исключениями?
Ошибки — непредвиденные дефекты, с которыми чаще всего сталкиваются пользователи. Как правило, возникновение ошибок приводит к завершению работы программы. В этом случае важно не только сохранить лицо перед пользователем, но и проинформировать разработчика о возникшей ситуации для её дальнейшего устранения.
Исключения происходят по инициативе разработчиков в потенциальных местах, где могут возникнуть ошибки. Для выброса исключения разработчик вызывает функцию throw(), а в дальнейшем может осуществить перехват.
Как эти процессы протекают в Yii?
В Yii, не фатальные PHP ошибки (заметки и предупреждения) отлавливаются, что даёт возможность должным образом на них среагировать. Все эти исключения могут направляться на определённый экшен контроллера. Также вы можете повлиять на формат отображения данных ошибок: HTML, JSON, XML и т.д.
Исключения и фатальные PHP ошибки можно увидеть только если код работает в отладочном режиме. В этом случае Yii выведет всю подробную информацию об ошибке, включая фрагмент проблемного кода (пример показан в ковер-изображении к данному уроку).
Возникновение фатальных ошибок останавливает работу приложения. К примеру, может возникнуть ситуация нехватки памяти, произойти попытка создания объекта несуществующего класса или вызов неизвестной функции.
К примеру:
1 |
$t = new Unknownobject(); |
Давайте же рассмотрим парочку примеров, где мы покажем как можно отловить ошибки/исключения, и обработать их.
Конфигурация обработчика ошибок и исключений
Для начала нам нужно внести кое-какие записи в файл конфигурации frontend/config/main.php. Как показано ниже, в этом файле определён компонент errorHandler. Данный пример взят из моей серии по организации стартапа Meeting Planner. Взгляните на конфигурацию errorHandler в разделе components:
1 |
<?php
|
2 |
$params = array_merge( |
3 |
require(__DIR__ . '/params.php'), |
4 |
require(__DIR__ . '/params-local.php') |
5 |
);
|
6 |
return [ |
7 |
'id' => 'mp-frontend', |
8 |
'name' => 'Meeting Planner', |
9 |
'basePath' => dirname(__DIR__), |
10 |
'bootstrap' => ['log','\common\components\SiteHelper'], |
11 |
'controllerNamespace' => 'frontend\controllers', |
12 |
'catchAll'=> [], |
13 |
'components' => [ |
14 |
'assetManager' => [...], |
15 |
...
|
16 |
'errorHandler' => [ |
17 |
'errorAction' => 'site/error', |
18 |
'maxSourceLines' => 20, |
19 |
],
|
20 |
...
|
21 |
],
|
22 |
];
|
В вышеприведённом примере определено, что при возникновении ошибки errorAction направит пользователя на экшен error SiteController-а.
Если более подробно, то Yii предлагает целый ряд конфигурационных настроек к компоненту errorHandler для редиректа и обработки информации:
| Свойство | Тип | Описание |
|---|---|---|
| $callStackItemView | строка | Путь к файлу, в котором будет происходить рендеринг информации об ошибках. Пример: '@yii/views/errorHandler/callStackItem.php' |
| $displayVars | массив | Список определённых PHP переменных, которые должны отображаться в специальной секции отображения ошибок. Примеру: ['_GET', '_POST', '_FILES', '_COOKIE', '_SESSION'] |
| $errorAction | строка | Маршрут (site/error) к контроллеру и экшену в котором будут обрабатываться ошибки. |
| $errorView | строка | Путь к файлу, в котором будет происходить рендеринг информации об ошибках без подробного описания. Пример: '@yii/views/errorHandler/error.php' |
| $exceptionView | строка | Путь к файлу, в котором будет происходить рендеринг информации об исключениях. Пример: '@yii/views/errorHandler/exception.php' |
| $maxSourceLines | число | Максимальное число отображаемого исходного кода. |
| $maxTraceSourceLines | число | Максимальное число отображаемого исходного трэйс-кода. |
| $previousExceptionView | строка | Путь к файлу, в котором будет происходить рендеринг информации о предыдущем исключении. Пример: '@yii/views/errorHandler/previousException.php' |
Прямой вызов errorActions
В общем, в случае возникновения серьёзной ошибки мы бы хотели показать пользователю подробную информацию в удобном для восприятия виде.
Как раз-таки это и происходит в экшене errorAction класса errorHandler. С этой точки мы и будем направлены на SiteController -> actionError:
1 |
return [ |
2 |
'components' => [ |
3 |
'errorHandler' => [ |
4 |
'errorAction' => 'site/error', |
5 |
],
|
6 |
]
|
7 |
];
|
Определим экшен error в SiteController:
1 |
namespace app\controllers; |
2 |
|
3 |
use Yii; |
4 |
use yii\web\Controller; |
5 |
|
6 |
class SiteController extends Controller |
7 |
{
|
8 |
public function actions() |
9 |
{
|
10 |
return [ |
11 |
'error' => [ |
12 |
'class' => 'yii\web\ErrorAction', |
13 |
],
|
14 |
];
|
15 |
}
|
16 |
}
|
Вот так вот будет выглядеть обработка ошибки (ссылка на более подробную информацию):
1 |
public function actionError() |
2 |
{
|
3 |
$exception = Yii::$app->errorHandler->exception; |
4 |
if ($exception !== null) { |
5 |
return $this->render('error', ['exception' => $exception]); |
6 |
}
|
7 |
}
|
Также вы можете точно определить, возникла ли ошибка или в вашем приложении не существует запрашиваемого маршрута:
1 |
public function actionError() |
2 |
{
|
3 |
$exception = Yii::$app->errorHandler->exception; |
4 |
if ($exception instanceof \yii\web\NotFoundHttpException) { |
5 |
// all non existing controllers+actions will end up here
|
6 |
return $this->render('pnf'); // page not found |
7 |
} else { |
8 |
return $this->render('error', ['exception' => $exception]); |
9 |
}
|
10 |
}
|
Вот мой обработчик ошибки Page Not Found 404:



Никто не запрещает на странице описания ошибки оставить свои контакты или показать материалы схожие с пользовательским запросом. Все эти меры увеличивают шансы сохранить своё лицо перед пользователем.
Вот моя страница с отображением ошибки (конечно же над ней нужно ещё работать и работать):



Обработка исключений
Для обработки исключений можем воспользоваться PHP-шной конструкцией try catch. Давайте посмотрим пример в котором разделим число на ноль:
1 |
use Yii; |
2 |
use yii\base\ErrorException; |
3 |
|
4 |
...
|
5 |
|
6 |
try { |
7 |
10/0; |
8 |
} catch (ErrorException $e) { |
9 |
Yii::warning("Division by zero."); |
10 |
}
|
11 |
|
12 |
...
|
В блоке catch запишем предупреждение в лог. В Yii есть несколько методов логирования:
- Yii::trace(): сообщение с куском кода. Обычно используется во время разработки.
- Yii::info(): информационное сообщение.
- Yii::warning(): предупреждение о каком-то событии.
- Yii::error(): сообщение о фатальной ошибке.
Если же вам не нужно записывать событие в лог, а просто перенаправить пользователя на страницу с информацией об ошибке, то этих строчек будет достаточно:
1 |
use yii\web\NotFoundHttpException; |
2 |
|
3 |
throw new NotFoundHttpException(); |
Вот пример в котором мы выбрасываем исключение с определённым HTTP кодом и специальным сообщением:
1 |
try { |
2 |
10/0; |
3 |
} catch (ErrorException $e) { |
4 |
throw new \yii\web\HttpException(451, |
5 |
'Tom McFarlin\'s humor is often lost on me
|
6 |
(and lots of people).'); |
7 |
}
|
А вот что в этом случае увидит пользователь:



О логировании в Yii
Все ошибки в Yii логируются в зависимости от того, как вы их организуете и настроите. Если данная тема вам интересна, то можете ознакомиться с другими моими уроками по Yii:
Заключение
Надеюсь, что мне удалось раскрыть тему, и должным образом показать процесс обработки ошибок и исключений. Следите за обновлениями серии Разработка на базе Yii2, где мы затрагиваем различные аспекты работы с фрэймворком.
Если же вы хотите более глубоко нырнуть в изучении Yii, то советую ознакомиться с серией по Созданию стартапа на PHP, где активно используется компонент шаблонизатора Yii2. В данной серии описаны все этапы создания сервиса Meeting Planner. Для тех кто только начинает учить Yii — данный материал будет очень полезен.
Если вы хотите первыми узнать о выходе новых уроков по Yii2 подписывайтесь на мой Twitter @lookahead_io и персональную страницу.





