Ошибки PHP: классификация, примеры, обработка
В статье представлена очередная попытка разобраться с ошибками, которые могут встретиться на вашем пути php-разработчика, их возможная классификация, примеры их возникновения, влияние ошибок на ответ клиенту, а также инструкции по написанию своего обработчика ошибок.
Классификация ошибок
- Фатальные
Неустранимые ошибки. Работа скрипта прекращается.
E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR. - Не фатальные
Устранимые ошибки. Работа скрипта не прекращается.
E_WARNING, E_NOTICE, E_CORE_WARNING, E_COMPILE_WARNING, E_USER_WARNING, E_USER_NOTICE, E_STRICT, E_DEPRECATED, E_USER_DEPRECATED. - Смешанные
Фатальные, но только, если не обработаны функцией, определенной пользователем в set_error_handler().
E_USER_ERROR, E_RECOVERABLE_ERROR.
- Перехватываемые (не фатальные и смешанные)
E_USER_ERROR, E_RECOVERABLE_ERROR, E_WARNING, E_NOTICE, E_USER_WARNING, E_USER_NOTICE, E_STRICT, E_DEPRECATED, E_USER_DEPRECATED. - Не перехватываемые (фатальные)
E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING.
- Инициированы пользователем
E_USER_ERROR, E_USER_WARNING, E_USER_NOTICE. - Инициированы PHP
E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_WARNING, E_NOTICE, E_CORE_WARNING, E_COMPILE_WARNING, E_STRICT, E_DEPRECATED, E_USER_DEPRECATED, E_USER_ERROR, E_RECOVERABLE_ERROR.
Примеры возникновения ошибок
"; /* * перехватываемые ошибки (ловятся функцией set_error_handler()) */ // NONFATAL - E_NOTICE // echo $undefined_var; // NONFATAL - E_WARNING // array_key_exists('key', NULL); // NONFATAL - E_DEPRECATED split('[/.-]', "12/21/2012"); // split() deprecated начиная с php 5.3.0 // NONFATAL - E_STRICT // class c > c::f(); // NONFATAL - E_USER_DEPRECATED // trigger_error("E_USER_DEPRECATED", E_USER_DEPRECATED); // NONFATAL - E_USER_WARNING // trigger_error("E_USER_WARNING", E_USER_WARNING); // NONFATAL - E_USER_NOTICE // trigger_error("E_USER_NOTICE", E_USER_NOTICE); // FATAL, если не обработана функцией set_error_handler - E_RECOVERABLE_ERROR // class b > $b = new b; $b->f(NULL); // FATAL, если не обработана функцией set_error_handler - E_USER_ERROR // trigger_error("E_USER_ERROR", E_USER_ERROR); /* * неперехватываемые (не ловятся функцией set_error_handler()) */ // FATAL - E_ERROR // undefined_function(); // FATAL - E_PARSE // parse_error // FATAL - E_COMPILE_ERROR // $var[]; echo "Файл с ошибками. Конец
";
Примечание: для полной работоспособности скрипта необходим PHP версии не ниже 5.3.0.
В файле errors.php представлены выражения, инициирующие практически все возможные ошибки. Исключение составили: E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_WARNING, генерируемые ядром Zend. В теории, встретить их в реальной работе вы не должны.
В следующей таблице приведены варианты поведения этого скрипта в различных условиях (в зависимости от значений директив display_errors и error_reporting):
Группа ошибок | Значения директив * | Статус ответа сервера | Ответ клиенту ** |
---|---|---|---|
E_PARSE, E_COMPILE_ERROR *** | display_errors = off error_reporting = ANY | 500 | Пустое значение |
display_errors = on error_reporting = ANY | 200 | Сообщение об ошибке | |
E_USER_ERROR, E_ERROR, E_RECOVERABLE_ERROR | display_errors = off error_reporting = ANY | 500 | Вывод скрипта до ошибки |
display_errors = on error_reporting = ANY | 200 | Сообщение об ошибке и вывод скрипта до ошибки | |
Не фатальные ошибки | display_errors = off error_reporting = ANY и display_errors = on error_reporting = 0 | 200 | Весь вывод скрипта |
display_errors = on error_reporting = E_ALL | E_STRICT | 200 | Сообщение об ошибке и весь вывод скрипта |
* Значение ANY означает E_ALL | E_STRICT или 0.
** Ответ клиенту может отличаться от ответов на реальных скриптах. Например, вывод какой-либо информации до включения файла errors.php, будет фигурировать во всех рассмотренных случаях.
*** Если в файле errors.php заменить пример для ошибки E_COMPILE_ERROR на require «missing_file.php»; , то ошибка попадет во вторую группу.
- Наличие в файле скрипта ошибки, приводящей его в «негодное» состояние (невозможность корректно обработать), на выходе даст пустое значение или же только само сообщение об ошибке, в зависимости от значения директивы display_errors.
- Скрипт в файле с фатальной ошибкой, не относящейся к первому пункту, будет выполняться в штатном режиме до самой ошибки.
- Наличие в файле фатальной ошибки при display_errors = Off обозначит 500 статус ответа.
- Не фатальные ошибки, как и следовало ожидать, в контексте возможности исполнения скрипта в целом, на работоспособность не повлияют.
Собственный обработчик ошибок
- для получения информации о последней произошедшей ошибке существует функция error_get_last();
- для определения собственного обработчика ошибок существует функция set_error_handler(), но фатальные ошибки нельзя «перехватить» этой функцией;
- используя register_shutdown_function(), можно зарегистрировать свою функцию, выполняемую по завершении работы скрипта, и в ней, используя знания из первого пункта, если фатальная ошибка имела место быть, предпринять необходимые действия;
- сообщение о фатальной ошибке в любом случае попадет в буфер вывода;
- воспользовавшись функциями контроля вывода можно предотвратить отображение нежелательной информации;
- при использовании оператора управления ошибками (знак @) функция, определенная в set_error_handler() все равно будет вызвана, но функция error_reporting() в этом случае вернет 0, чем и можно пользоваться для прекращения работы или определения другого поведения своего обработчика ошибок.
'E_ERROR', E_WARNING => 'E_WARNING', E_PARSE => 'E_PARSE', E_NOTICE => 'E_NOTICE', E_CORE_ERROR => 'E_CORE_ERROR', E_CORE_WARNING => 'E_CORE_WARNING', E_COMPILE_ERROR => 'E_COMPILE_ERROR', E_COMPILE_WARNING => 'E_COMPILE_WARNING', E_USER_ERROR => 'E_USER_ERROR', E_USER_WARNING => 'E_USER_WARNING', E_USER_NOTICE => 'E_USER_NOTICE', E_STRICT => 'E_STRICT', E_RECOVERABLE_ERROR => 'E_RECOVERABLE_ERROR', E_DEPRECATED => 'E_DEPRECATED', E_USER_DEPRECATED => 'E_USER_DEPRECATED', ); // выводим свое сообщение об ошибке echo " [$errno] $errstr ($errfile на $errline строке)
\n"; > // не запускаем внутренний обработчик ошибок PHP return TRUE; > /** * Функция перехвата фатальных ошибок */ function fatal_error_handler() < // если была ошибка и она фатальна if ($error = error_get_last() AND $error['type'] & ( E_ERROR | E_PARSE | E_COMPILE_ERROR | E_CORE_ERROR)) < // очищаем буффер (не выводим стандартное сообщение об ошибке) ob_end_clean(); // запускаем обработчик ошибок error_handler($error['type'], $error['message'], $error['file'], $error['line']); >else < // отправка (вывод) буфера и его отключение ob_end_flush(); >> // определеяем уровень протоколирования ошибок error_reporting(E_ALL | E_STRICT); // определяем режим вывода ошибок ini_set('display_errors', 'On'); // включаем буфферизацию вывода (вывод скрипта сохраняется во внутреннем буфере) ob_start(); // устанавливаем пользовательский обработчик ошибок set_error_handler("error_handler"); // регистрируем функцию, которая выполняется после завершения работы скрипта (например, после фатальной ошибки) register_shutdown_function('fatal_error_handler'); require 'errors.php';
Не забываем, что ошибки смешанного типа, после объявления собственного обработчика ошибок, стали не фатальными. Плюс к этому, весь вывод скрипта до фатальной ошибки вместе с стандартным сообщением об ошибке будет сброшен.
Вообще, рассмотренный пример обработчика ошибок, обработкой, как таковой, не занимается, а только демонстрирует саму возможность. Дальнейшее его поведение зависит от ваших желаний и/или требований. Например, все случаи обращения к обработчику можно записывать в лог, а в случае фатальных ошибок, дополнительно, уведомлять об этом администратора ресурса.
Полезные ссылки
- Первоисточник: php.net/manual/ru/book.errorfunc.php
- Описание ошибок: php.net/manual/ru/errorfunc.constants.php
- Функции контроля вывода: php.net/manual/ru/ref.outcontrol.php
- Побитовые операторы: php.net/manual/ru/language.operators.bitwise.php и habrahabr.ru/post/134557
- Тематически близкая статья: habrahabr.ru/post/134499
Предопределённые константы
Перечисленные ниже константы всегда доступны как часть ядра PHP.
Замечание: Данные имена констант можно использовать в файле php.ini но не вне PHP, как например в файле httpd.conf , где вместо них необходимо использовать значения их битовых масок.
Значение | Константа | Описание | Примечание |
---|---|---|---|
1 | E_ERROR ( int ) | Фатальные ошибки времени выполнения. Это неустранимые средствами самого скрипта ошибки, такие как ошибка распределения памяти и т.п. Выполнение скрипта в таком случае прекращается. | |
2 | E_WARNING ( int ) | Предупреждения времени выполнения (не фатальные ошибки). Выполнение скрипта в таком случае не прекращается. | |
4 | E_PARSE ( int ) | Ошибки на этапе компиляции. Должны генерироваться только парсером. | |
8 | E_NOTICE ( int ) | Уведомления времени выполнения. Указывают на то, что во время выполнения скрипта произошло что-то, что может указывать на ошибку, хотя это может происходить и при обычном выполнении программы. | |
16 | E_CORE_ERROR ( int ) | Фатальные ошибки, которые происходят во время запуска РНР. Такие ошибки схожи с E_ERROR , за исключением того, что они генерируются ядром PHP. | |
32 | E_CORE_WARNING ( int ) | Предупреждения (не фатальные ошибки), которые происходят во время начального запуска РНР. Такие предупреждения схожи с E_WARNING , за исключением того, что они генерируются ядром PHP. | |
64 | E_COMPILE_ERROR ( int ) | Фатальные ошибки на этапе компиляции. Такие ошибки схожи с E_ERROR , за исключением того, что они генерируются скриптовым движком Zend. | |
128 | E_COMPILE_WARNING ( int ) | Предупреждения на этапе компиляции (не фатальные ошибки). Такие предупреждения схожи с E_WARNING , за исключением того, что они генерируются скриптовым движком Zend. | |
256 | E_USER_ERROR ( int ) | Сообщения об ошибках, сгенерированные пользователем. Такие ошибки схожи с E_ERROR , за исключением того, что они генерируются в коде скрипта средствами функции PHP trigger_error() . | |
512 | E_USER_WARNING ( int ) | Предупреждения, сгенерированные пользователем. Такие предупреждения схожи с E_WARNING , за исключением того, что они генерируются в коде скрипта средствами функции PHP trigger_error() . | |
1024 | E_USER_NOTICE ( int ) | Уведомления, сгенерированные пользователем. Такие уведомления схожи с E_NOTICE , за исключением того, что они генерируются в коде скрипта, средствами функции PHP trigger_error() . | |
2048 | E_STRICT ( int ) | Включаются для того, чтобы PHP предлагал изменения в коде, которые обеспечат лучшее взаимодействие и совместимость кода. | |
4096 | E_RECOVERABLE_ERROR ( int ) | Фатальные ошибки с возможностью обработки. Такие ошибки указывают, что, вероятно, возникла опасная ситуация, но при этом, скриптовый движок остаётся в стабильном состоянии. Если такая ошибка не обрабатывается функцией, определённой пользователем для обработки ошибок (смотрите set_error_handler() ), выполнение приложения прерывается, как происходит при ошибках E_ERROR . | |
8192 | E_DEPRECATED ( int ) | Уведомления времени выполнения об использовании устаревших конструкций. Включаются для того, чтобы получать предупреждения о коде, который не будет работать в следующих версиях PHP. | |
16384 | E_USER_DEPRECATED ( int ) | Уведомления времени выполнения об использовании устаревших конструкций, сгенерированные пользователем. Такие уведомления схожи с E_DEPRECATED за исключением того, что они генерируются в коде скрипта, с помощью функции PHP trigger_error() . | |
32767 | E_ALL ( int ) | Все поддерживаемые ошибки, предупреждения и замечания. |
Представленные выше значения (как числовые, так и символьные) используются для задания битовой маски, определяющей об ошибках какого типа будет даваться отчёт. Вы можете использовать побитовые операторы, чтобы совмещать эти значения для указания определённых типов ошибок. Стоит отметить, что в php.ini допустимы только следующие операторы: ‘|’, ‘~’, ‘!’, ‘^’ и ‘&’.