Ошибки 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
henriquemoody / http-status-codes.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
/** |
* Content from http://en.wikipedia.org/wiki/List_of_HTTP_status_codes |
* |
* You may also want a list of unofficial codes: |
* |
* 103 => ‘Checkpoint’, |
* 218 => ‘This is fine’, // Apache Web Server |
* 419 => ‘Page Expired’, // Laravel Framework |
* 420 => ‘Method Failure’, // Spring Framework |
* 420 => ‘Enhance Your Calm’, // Twitter |
* 430 => ‘Request Header Fields Too Large’, // Shopify |
* 450 => ‘Blocked by Windows Parental Controls’, // Microsoft |
* 498 => ‘Invalid Token’, // Esri |
* 499 => ‘Token Required’, // Esri |
* 509 => ‘Bandwidth Limit Exceeded’, // Apache Web Server/cPanel |
* 526 => ‘Invalid SSL Certificate’, // Cloudflare and Cloud Foundry’s gorouter |
* 529 => ‘Site is overloaded’, // Qualys in the SSLLabs |
* 530 => ‘Site is frozen’, // Pantheon web platform |
* 598 => ‘Network read timeout error’, // Informal convention |
* 440 => ‘Login Time-out’, // IIS |
* 449 => ‘Retry With’, // IIS |
* 451 => ‘Redirect’, // IIS |
* 444 => ‘No Response’, // nginx |
* 494 => ‘Request header too large’, // nginx |
* 495 => ‘SSL Certificate Error’, // nginx |
* 496 => ‘SSL Certificate Required’, // nginx |
* 497 => ‘HTTP Request Sent to HTTPS Port’, // nginx |
* 499 => ‘Client Closed Request’, // nginx |
* 520 => ‘Web Server Returned an Unknown Error’, // Cloudflare |
* 521 => ‘Web Server Is Down’, // Cloudflare |
* 522 => ‘Connection Timed Out’, // Cloudflare |
* 523 => ‘Origin Is Unreachable’, // Cloudflare |
* 524 => ‘A Timeout Occurred’, // Cloudflare |
* 525 => ‘SSL Handshake Failed’, // Cloudflare |
* 526 => ‘Invalid SSL Certificate’, // Cloudflare |
* 527 => ‘Railgun Error’, // Cloudflare |
*/ |
return [ |
100 => ‘Continue’ , |
101 => ‘Switching Protocols’ , |
102 => ‘Processing’ , // WebDAV; RFC 2518 |
103 => ‘Early Hints’ , // RFC 8297 |
200 => ‘OK’ , |
201 => ‘Created’ , |
202 => ‘Accepted’ , |
203 => ‘Non-Authoritative Information’ , // since HTTP/1.1 |
204 => ‘No Content’ , |
205 => ‘Reset Content’ , |
206 => ‘Partial Content’ , // RFC 7233 |
207 => ‘Multi-Status’ , // WebDAV; RFC 4918 |
208 => ‘Already Reported’ , // WebDAV; RFC 5842 |
226 => ‘IM Used’ , // RFC 3229 |
300 => ‘Multiple Choices’ , |
301 => ‘Moved Permanently’ , |
302 => ‘Found’ , // Previously «Moved temporarily» |
303 => ‘See Other’ , // since HTTP/1.1 |
304 => ‘Not Modified’ , // RFC 7232 |
305 => ‘Use Proxy’ , // since HTTP/1.1 |
306 => ‘Switch Proxy’ , |
307 => ‘Temporary Redirect’ , // since HTTP/1.1 |
308 => ‘Permanent Redirect’ , // RFC 7538 |
400 => ‘Bad Request’ , |
401 => ‘Unauthorized’ , // RFC 7235 |
402 => ‘Payment Required’ , |
403 => ‘Forbidden’ , |
404 => ‘Not Found’ , |
405 => ‘Method Not Allowed’ , |
406 => ‘Not Acceptable’ , |
407 => ‘Proxy Authentication Required’ , // RFC 7235 |
408 => ‘Request Timeout’ , |
409 => ‘Conflict’ , |
410 => ‘Gone’ , |
411 => ‘Length Required’ , |
412 => ‘Precondition Failed’ , // RFC 7232 |
413 => ‘Payload Too Large’ , // RFC 7231 |
414 => ‘URI Too Long’ , // RFC 7231 |
415 => ‘Unsupported Media Type’ , // RFC 7231 |
416 => ‘Range Not Satisfiable’ , // RFC 7233 |
417 => ‘Expectation Failed’ , |
418 => ‘I\’m a teapot’ , // RFC 2324, RFC 7168 |
421 => ‘Misdirected Request’ , // RFC 7540 |
422 => ‘Unprocessable Entity’ , // WebDAV; RFC 4918 |
423 => ‘Locked’ , // WebDAV; RFC 4918 |
424 => ‘Failed Dependency’ , // WebDAV; RFC 4918 |
425 => ‘Too Early’ , // RFC 8470 |
426 => ‘Upgrade Required’ , |
428 => ‘Precondition Required’ , // RFC 6585 |
429 => ‘Too Many Requests’ , // RFC 6585 |
431 => ‘Request Header Fields Too Large’ , // RFC 6585 |
451 => ‘Unavailable For Legal Reasons’ , // RFC 7725 |
500 => ‘Internal Server Error’ , |
501 => ‘Not Implemented’ , |
502 => ‘Bad Gateway’ , |
503 => ‘Service Unavailable’ , |
504 => ‘Gateway Timeout’ , |
505 => ‘HTTP Version Not Supported’ , |
506 => ‘Variant Also Negotiates’ , // RFC 2295 |
507 => ‘Insufficient Storage’ , // WebDAV; RFC 4918 |
508 => ‘Loop Detected’ , // WebDAV; RFC 5842 |
510 => ‘Not Extended’ , // RFC 2774 |
511 => ‘Network Authentication Required’ , // RFC 6585 |
]; |