Меню

Php обработка 500 ошибок

  • Предыдующая статья: Делаем собственную страницу ошибки 404

Лого sayt-sozdat.ru

2019-12-01

Здравствуйте, уважаемый посетитель!

Сегодня в рамах рассмотрения системы обработки ошибок выполним необходимые действия по выводу пользователю сообщения о возникновении внутренней ошибки сервера Internal Server Error, соответствующей статусу HTTP 500.

Это необходимо сделать, так как никто не застрахован от возникновения подобных проблем. В таких случаях, если не предпринять соответстующих мер, пользователь в своем браузере будет видеть только лишь какой-нибудь ущербный, неполноценный вариант веб-страницы. Либо вообще пустой экран или страницу в несколько строк с непонятными для него техническими терминами.

И вот для того, чтобы упорядочить работу сайта, обеспечивая пользователя при любых ситуациях необходимой информацией, мы создадим собственную страницу 500.

А затем, для обеспечения на нее перенаправления, сформируем пользовательский обработчик фатальных ошибок PHP. Который в дальнейшем поможет нам обеспечить и другие возможности создаваемого механизма, такие как сохранение логов и отправка сообщений по email.

  • Создание страницы 500
  • Перехват и обработка фатальных ошибок PHP
  • Буферизация вывода в PHP
  • Дополнение файла .htaccess
  • Проверка работы сайта при внутренней ошибке сервера
  • Исходные файлы сайта

Создание страницы 500


В первую очередь создадим в корне сайта новый файл с соответствующим именем, например «page_500.php». И поместим в него код страницы, которая будет отображаться при возникновении ошибки 500. А выполним это аналогично тому, как мы это делали в предыдущей статье при создании страницы 404.

Правда, сделаем это с некоторым отличием, заключающимся в том, что в этот раз при ее формировании будем использовать только разметку HTML, исключая какое-либо использование PHP.

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

Конечно, это не относится к применению функции header(), с помощью которой отправляется HTTP заголовок с кодом 500, соответствующий внутренней ошибки сервера (строка 2 в приведенном ниже коде).

kak-vyvesti-stranicu-oshibki-500_1

Рис.1 Файл «page_500.php» с HTML-кодом страницы 500

Как видно, данный вариант по структуре полностью соответствует предыдущей странице 404, но выполнен на чистом HTML. Причем все общие блоки: шапка, меню, основное содержание и футер включены непосредственно, без применения подключающих инструкций PHP.

Что касается оформления, то в данном случае этого не требуется, так HTML-код страницы мало чем отличается от предыдущей. И как следствие, все необходимые свойства уже ранее назначены и добавлены в таблицу стилей CSS.

И в этом можно убедиться, если сейчас открыть созданную страницу через адресную строку браузера, добавив к доменному имени ее адрес /page_500.php. Как и в предыдущем случае в начале сделаем это в обычном, десктопном варианте пользовательского устройства.

Вид созданной страницы 500

Рис.2 Вид созданной страницы 500

А теперь посмотрим как это будет выглядеть при малом разрешении экрана в одно колоночном исполнении.

Вид страницы 500 при малом разрешении экрана

Рис.3 Вид страницы 500 при малом разрешении экрана

Как видно, полученная страница по форме схожа с предыдущей 404. За исключением содержания, отражающего теперь информацию о возникновении внутренней ошибки сервера, соответствующей статусу 500 протокола HTTP.

Таким образом необходимая страница создана. И теперь осталось только обеспечить на нее перенаправление.

Перехват и обработка фатальных ошибок PHP


Как ранее отмечалось, внутренняя ошибка сервера наиболее часто возникает в следствии фатальных ошибок PHP. Причем такие случаи обычно сопровождаются остановкой скрипта. Отчего идентифицировать такую ошибку с помощью того же самого скрипта не получится. Так как в этом случае выполнение в нем каких-либо последующих действий не представляется возможным.

Как вариант решения этой проблемы — применение встроенной функции обратного вызова register_shutdown_function(), предназначенной для регистрации специальной пользовательской функции, не связанной с работой скрипта. И, следовательно, способной выполнить дальнейшие преобразования, несмотря на то, что сам скрипт остановлен.

И таким образом, в случае возникновения фатальной ошибки управление передается этой зарегистрированной функции, являющейся в данном случае обработчиком.

Как может выглядеть регистрация пользовательской функции и перехват в ней последней ошибки, остановившей работу скрипта, показано в следующем фрагменте PHP-кода.

  1. //—-Перехват и обработка фатальных ошибок PHP—-

  2. function fatal_php(){ //Пользовательская функция

  3. $error = error_get_last(); //Получение информации о последней произошедшей ошибке

  4. if ($error !== NULL && in_array($error[‘type’], array(E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR))){ //Если ошибка произошла и ее тип соответствует фатальной ошибке

  5. $domen = ‘http://’.$_SERVER[‘SERVER_NAME’]; //Домен сайта

  6. header(«Location: $domen/page_500.php»); //Редирект на страницу 500

  7. exit; //Прекращение выполнения текущего скрипта

  8. }

  9. }

  10. register_shutdown_function(‘fatal_php’); //Регистрация пользовательской функции обработчика фатальных ошибок PHP

  11. ?>

Рис.4 Перехват и обработка фатальных ошибок PHP

Здесь все строки кода сопровождаются комментариями, поэтому подробно описывать каждую из них, нет смысла.

Можно лишь отметить, что регистрация пользовательской функции выполняется, как ранее было отмечено, с помощью register_shutdown_function(), расположенной в строке 11.

А сама функция обработчика с именем fatal_php() (поз.3÷10) в начале возвращает ассоциативный массив с описанием последней произошедшей ошибки (функция error_get_last() поз.4). А затем в случае, если выявленная ошибка относится к одному из четырех необходимых типов (E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR), то с помощью функции отправки HTTP-заголовка header() (поз.7) выполняется редирект по указанному аргументом «Location» адресу, соответствующему странице 500.

В случае, если фатальная ошибка PHP возникает в процессе формирования тела страницы при отправленном HTTP-заголовке, то при установках по умолчанию, в соответствии с протоколом HTTP должна возникнуть ошибка Cannot modify header information — headers already sent by (), означающая невозможность изменения заголовка после его отправки. Более подробно об этом и о том, как решить эту проблему мы посмотрим в следующем разделе статьи.

Таким образом при использовании созданной пользовательской функции, в случае, если из-за какой-то критической ошибки PHP-скрипт остановлен, обработчик ее обнаружит и выполнит необходимые действия по ее идентификации и дальнейшей обработке.

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

И последнее, на что необходимо обратить внимание, функция обработчика должна быть расположена в самом начале кода шаблона главной страницы файла index.php. Иными словами, чтобы все остальные PHP-инструкции, используемые при формировании веб-страницы, выполнялись только после ее регистрации. В противном случае при остановке скрипта обработчик не будет вызван и, соответственно, не сможет выполнить свою задачу.

Буферизация вывода в PHP


В созданном обработчике фатальных ошибок PHP (рис.2) с помощью функции HTTP-заголовка header() (поз.7) предусматривается редирект на страницу 500.

Однако, здесь следует учесть одно обстоятельство, а именно: в случае редиректа, выполняемого в момент формирования тела веб-страницы, уже после отправки HTTP-заголовка, непременно должна последовать ошибка Cannot modify header information — headers already sent by ().

Обусловлено это следующим. По умолчанию сервер отправляет в браузер данные веб-страницы по мере их готовности, в процессе выполнения PHP-скрипта. При этом в соответствии с протоколом HTTP, сервер в ответ на запрос должен в первую очередь отправить служебные заголовки, а уж только потом код самого тела страницы. И протоколом HTTP не допускается ситуация, когда в момент передачи тела страницы производится повторная оправка HTTP-заголовка. О чем и говорит описание вышеуказанной ошибки.

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

На скриншоте показан вариант вывода страницы «Получить скидку», у которой в код PHP файла poluchit-skidku.php специально внесена синтаксическая ошибка.

Ошибка при изменении заголовка после его отправки

Рис.5 Ошибка при изменении заголовка после его отправки

Как видно, здесь в области основного содержания, при обнаружении в ней фатальной ошибки Parse error и остановки скрипта, присутствует также и ошибка Cannot modify header information — headers already sent by (), означающая невозможность изменения заголовка в момент передачи кода данного блока веб-страницы.

А для того, чтобы решить эту проблему и иметь возможность изменять в любой момент HTTP-заголовки, применяется, так называемая буферизация вывода в PHP.

Суть ее в том, что в этом случае при выполнении PHP, сервер не оправляет страницу по мере ее готовности, а складывает полученный код в определенный буфер, параллельно формируя HTTP-заголовки, которые в обычном режиме не допускается оправлять в момент передачи тела страницы.

И только после того, как скрипт выполнит все заложенные в него операции, то всё, что в конечном итоге оказалось в буфере, разом отправляется в браузер пользователя в правильном порядке, как это определенно протоколом HTTP — сначала заголовки, а уж потом страница, сформированная скриптом.

В PHP существуют несколько функций, предназначенных для работы с буфером. Но для данной задачи мы будем использовать только две из них ob_start() — для включения буферизации вывода и ob_end_flush() — для отправки данных из буфера и отключения буферизации.

Схематично для генерируемой HTML-страницы это можно представить следующим образом.

kak-vyvesti-stranicu-oshibki-500_2

Рис.6 Буферизация вывода в PHP

А ниже показано, как в итоге будет выглядеть код шаблона главной страницы в файле index.php после дополнения его обработчиком фатальных ошибок PHP и элементами буферизации вывода PHP (светлым фоном обозначены дополнительные фрагмента кода).

kak-vyvesti-stranicu-oshibki-500_3

Рис.7 Файл index.php с обработчиком ошибок и буферизацией вывода

Следует отметить, что для оптимизации файла index.php, ранее размещенный в начале шаблона главной страницы PHP-код, предназначенный для получения данных при формировании динамической страницы, перенесен в файл start.php, который подключается соответствующей инструкцией в строке 13.

Таким образом буферизацию вывода HTML-страницы, генерированной скриптом PHP, мы выполнили. Однако, для полноценной работы сайта при обработке ошибки 500 необходимо сделать еще одно небольшое дополнение, которые мы сейчас и рассмотрим.

Дополнение файла .htaccess


Приведенные выше преобразования предназначены для выполнения редиректа на страницу 500 в случае прерывания работы скрипта при фатальных ошибках PHP.

Но для того, чтобы это происходило и в других случаях внутренней ошибки сервера, необходимо в файл .htaccess добавить директиву ErrorDocument, аналогичную той, которую мы использовали ранее при редиректе на страницу 404. Только теперь в ней должен быть указан соответствующий адрес /page_500.php.

А заодно, в целях безопасности полезно будет вообще отключить отображение системных сообщений на экране пользователя. Так как теперь возникающие по каким-либо причинам ошибки будут фиксироваться собственным механизмом обработки ошибок и нет необходимости их выводить в браузер. Тем более, что в определенных случаях такая излишняя для пользователя информация может быть использована недоброжелателями в качестве уязвимости сайта.

В итоге файл .htaccess следует дополнить следующими директивами, которые обеспечат выполнение вышеперечисленных действий.

  1. ErrorDocument 500 /page_500.php

  2. php_flag display_errors 0

Рис.8 Редирект 500 в файле .htaccess

Таким образом мы сделали все необходимые преобразования для вывода страницы 500. И теперь можно проверить, как это в реальности будет работать.

Проверка работы сайта при внутренней ошибке сервера


Проверку обработки внутренней ошибки сервера выполним на примере возникновения фатальной ошибки PHP, что позволит удостовериться в корректной работе, как созданного обработчики фатальных ошибок, так и процесса буферизации вывода генерируемой страницы и редиректа на страницу 500.

Для этого в код PHP временно внесем ту же самую синтаксическую ошибку, которую ранее мы делали на промежуточном этапе (рис.5). И посмотрим, как теперь будет обработана такая ситуация.

Вывод страницы 500 при фатальной ошибке PHP

Рис.9 Вывод страницы 500 при фатальной ошибке PHP

Как видно, теперь критическая ошибка отработана должным образом, с перенаправлением на страницу ошибки 500.

При желании, можно проверить работу сайта и при других искусственно созданных фатальных ошибках. И во всех случаях результат должен быть один — отображение собственной страницы 500. Что в итоге и требовалось получить.

В следующей статье мы создадим механизм обработки не фатальных ошибок PHP, где с помощью собственного обработчика будет обеспечиваться их перехват и сохранение сообщений в соответствующем журнале.

.

Исходные файлы сайта


Знак папкиИсходные файлы сайта с обновлениями, которые были сделаны в данной статье, можно скачать из прилагаемых дополнительных материалов:

  • Файлы каталога www
  • Таблицы базы данных MySQL

Дополнительные материалы бесплатно предоставляются только зарегистрированным пользователям.

Для скачивания исходных файлов необходимо авторизоваться под своим аккаунтом через соответствующую форму.

Для тех кто не зарегистрирован, можно это сделать на вкладке Регистрация.

С уважением,

  • Следующая сатья: Перехват и обработка не фатальных ошибок PHP

Если у Вас возникли вопросы, или есть какие-либо пожелания по представлению материала, либо заметили какие-нибудь ошибки, а быть может просто хотите выразить свое мнение, пожалуйста, оставьте свои комментарии. Такая обратная связь очень важна для возможности учета мнения посетителей.

Буду Вам за это очень признателен!

  • Главная»
  • Уроки»

  • PHP»

  • Создаем единую страницу для обработки ошибок
  • Метки урока:
  • php
  • кодинг
  • разное

Создаем единую страницу для обработки ошибок

В данном уроке представлено очень простое решение для обработки различных ошибок HTTP, таких как 404, 500 и так далее, в одном файле PHP. Нужно создать массив кодов ошибок и установить правила перенаправления на наш PHP файл. То есть, можно использовать одну страницу для обработки нескольких ошибок.

Перенаправление

В файле .htaccess вашего сервера нужно установить правила для обработки ошибок. В нашем случае мы будем перенаправлять все ошибки в наш файл errors.php, который будет формировать страницу HTML для посетителя. Добавляем в файл .htaccess следующие правила:

ErrorDocument 400 /errors.php
ErrorDocument 403 /errors.php
ErrorDocument 404 /errors.php
ErrorDocument 405 /errors.php
ErrorDocument 408 /errors.php
ErrorDocument 500 /errors.php
ErrorDocument 502 /errors.php
ErrorDocument 504 /errors.php

PHP

Теперь создаем файл errors.php, который должен располагаться в корневом каталоге вашего сервера (так как такое его местоположение установлено в заданных нами выше правилах в файле .htaccess).

$status = $_SERVER['REDIRECT_STATUS'];
$codes = array(
       400 => array('400 Плохой запрос', 'Запрос не может быть обработан из-за синтаксической ошибки.'),
       403 => array('403 Запрещено', 'Сервер отказывает в выполнении вашего запроса.'),
       404 => array('404 Не найдено', 'Запрашиваемая страница не найдена на сервере.'),
       405 => array('405 Метод не допускается', 'Указанный в запросе метод не допускается для заданного ресурса.'),
       408 => array('408 Время ожидания истекло', 'Ваш браузер не отправил информацию на сервер за отведенное время.'),
       500 => array('500 Внутренняя ошибка сервера', 'Запрос не может быть обработан из-за внутренней ошибки сервера.'),
       502 => array('502 Плохой шлюз', 'Сервер получил неправильный ответ при попытке передачи запроса.'),
       504 => array('504 Истекло время ожидания шлюза', 'Вышестоящий сервер не ответил за установленное время.'),
);
 
$title = $codes[$status][0];
$message = $codes[$status][1];
if ($title == false || strlen($status) != 3) {
       $message = 'Код ошибки HTTP не правильный.';
}
 
echo '<h1>Внимание! Обнаружена ошибка '.$title.'!</h1>
<p>'.$message.'</p>';

Готово!

Конечно, код PHP может формировать и более информативную страницу для пользователя. При формировании разметки стоит учесть рекомендации для страниц, выводящих информацию об ошибках.


5 последних уроков рубрики «PHP»

  • Фильтрация данных с помощью zend-filter

    Когда речь идёт о безопасности веб-сайта, то фраза «фильтруйте всё, экранируйте всё» всегда будет актуальна. Сегодня поговорим о фильтрации данных.

  • Контекстное экранирование с помощью zend-escaper

    Обеспечение безопасности веб-сайта — это не только защита от SQL инъекций, но и протекция от межсайтового скриптинга (XSS), межсайтовой подделки запросов (CSRF) и от других видов атак. В частности, вам нужно очень осторожно подходить к формированию HTML, CSS и JavaScript кода.

  • Подключение Zend модулей к Expressive

    Expressive 2 поддерживает возможность подключения других ZF компонент по специальной схеме. Не всем нравится данное решение. В этой статье мы расскажем как улучшили процесс подключение нескольких модулей.

  • Совет: отправка информации в Google Analytics через API

    Предположим, что вам необходимо отправить какую-то информацию в Google Analytics из серверного скрипта. Как это сделать. Ответ в этой заметке.

  • Подборка PHP песочниц

    Подборка из нескольких видов PHP песочниц. На некоторых вы в режиме online сможете потестить свой код, но есть так же решения, которые можно внедрить на свой сайт.

(PHP 5 >= 5.4.0, PHP 7, PHP 8)

http_response_codeGet or Set the HTTP response code

Description

http_response_code(int $response_code = 0): int|bool

Parameters

response_code

The optional response_code will set the response code.

Return Values

If response_code is provided, then the previous
status code will be returned. If response_code is not
provided, then the current status code will be returned. Both of these
values will default to a 200 status code if used in a web
server environment.

false will be returned if response_code is not
provided and it is not invoked in a web server environment (such as from a
CLI application). true will be returned if
response_code is provided and it is not invoked in a
web server environment (but only when no previous response status has been
set).

Examples

Example #1 Using http_response_code() in a web server environment


<?php// Get the current response code and set a new one
var_dump(http_response_code(404));// Get the new response code
var_dump(http_response_code());
?>

The above example will output:

Example #2 Using http_response_code() in a CLI environment


<?php// Get the current default response code
var_dump(http_response_code());// Set a response code
var_dump(http_response_code(201));// Get the new response code
var_dump(http_response_code());
?>

The above example will output:

bool(false)
bool(true)
int(201)

See Also

  • header() — Send a raw HTTP header
  • headers_list() — Returns a list of response headers sent (or ready to send)

craig at craigfrancis dot co dot uk

11 years ago


If your version of PHP does not include this function:

<?phpif (!function_exists('http_response_code')) {
        function
http_response_code($code = NULL) {

            if (

$code !== NULL) {

                switch (

$code) {
                    case
100: $text = 'Continue'; break;
                    case
101: $text = 'Switching Protocols'; break;
                    case
200: $text = 'OK'; break;
                    case
201: $text = 'Created'; break;
                    case
202: $text = 'Accepted'; break;
                    case
203: $text = 'Non-Authoritative Information'; break;
                    case
204: $text = 'No Content'; break;
                    case
205: $text = 'Reset Content'; break;
                    case
206: $text = 'Partial Content'; break;
                    case
300: $text = 'Multiple Choices'; break;
                    case
301: $text = 'Moved Permanently'; break;
                    case
302: $text = 'Moved Temporarily'; break;
                    case
303: $text = 'See Other'; break;
                    case
304: $text = 'Not Modified'; break;
                    case
305: $text = 'Use Proxy'; break;
                    case
400: $text = 'Bad Request'; break;
                    case
401: $text = 'Unauthorized'; break;
                    case
402: $text = 'Payment Required'; break;
                    case
403: $text = 'Forbidden'; break;
                    case
404: $text = 'Not Found'; break;
                    case
405: $text = 'Method Not Allowed'; break;
                    case
406: $text = 'Not Acceptable'; break;
                    case
407: $text = 'Proxy Authentication Required'; break;
                    case
408: $text = 'Request Time-out'; break;
                    case
409: $text = 'Conflict'; break;
                    case
410: $text = 'Gone'; break;
                    case
411: $text = 'Length Required'; break;
                    case
412: $text = 'Precondition Failed'; break;
                    case
413: $text = 'Request Entity Too Large'; break;
                    case
414: $text = 'Request-URI Too Large'; break;
                    case
415: $text = 'Unsupported Media Type'; break;
                    case
500: $text = 'Internal Server Error'; break;
                    case
501: $text = 'Not Implemented'; break;
                    case
502: $text = 'Bad Gateway'; break;
                    case
503: $text = 'Service Unavailable'; break;
                    case
504: $text = 'Gateway Time-out'; break;
                    case
505: $text = 'HTTP Version not supported'; break;
                    default:
                        exit(
'Unknown http status code "' . htmlentities($code) . '"');
                    break;
                }
$protocol = (isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0');header($protocol . ' ' . $code . ' ' . $text);$GLOBALS['http_response_code'] = $code;

            } else {

$code = (isset($GLOBALS['http_response_code']) ? $GLOBALS['http_response_code'] : 200);

            }

            return

$code;

        }
    }

?>

In this example I am using $GLOBALS, but you can use whatever storage mechanism you like... I don't think there is a way to return the current status code:

https://bugs.php.net/bug.php?id=52555

For reference the error codes I got from PHP's source code:

http://lxr.php.net/opengrok/xref/PHP_5_4/sapi/cgi/cgi_main.c#354

And how the current http header is sent, with the variables it uses:

http://lxr.php.net/opengrok/xref/PHP_5_4/main/SAPI.c#856


Stefan W

8 years ago


Note that you can NOT set arbitrary response codes with this function, only those that are known to PHP (or the SAPI PHP is running on).

The following codes currently work as expected (with PHP running as Apache module):
200 – 208, 226
300 – 305, 307, 308
400 – 417, 422 – 424, 426, 428 – 429, 431
500 – 508, 510 – 511

Codes 0, 100, 101, and 102 will be sent as "200 OK".

Everything else will result in "500 Internal Server Error".

If you want to send responses with a freestyle status line, you need to use the `header()` function:

<?php header("HTTP/1.0 418 I'm A Teapot"); ?>


Thomas A. P.

7 years ago


When setting the response code to non-standard ones like 420, Apache outputs 500 Internal Server Error.

This happens when using header(0,0,420) and http_response_code(420).
Use header('HTTP/1.1 420 Enhance Your Calm') instead.

Note that the response code in the string IS interpreted and used in the access log and output via http_response_code().


Anonymous

9 years ago


Status codes as an array:

<?php
$http_status_codes
= array(100 => "Continue", 101 => "Switching Protocols", 102 => "Processing", 200 => "OK", 201 => "Created", 202 => "Accepted", 203 => "Non-Authoritative Information", 204 => "No Content", 205 => "Reset Content", 206 => "Partial Content", 207 => "Multi-Status", 300 => "Multiple Choices", 301 => "Moved Permanently", 302 => "Found", 303 => "See Other", 304 => "Not Modified", 305 => "Use Proxy", 306 => "(Unused)", 307 => "Temporary Redirect", 308 => "Permanent Redirect", 400 => "Bad Request", 401 => "Unauthorized", 402 => "Payment Required", 403 => "Forbidden", 404 => "Not Found", 405 => "Method Not Allowed", 406 => "Not Acceptable", 407 => "Proxy Authentication Required", 408 => "Request Timeout", 409 => "Conflict", 410 => "Gone", 411 => "Length Required", 412 => "Precondition Failed", 413 => "Request Entity Too Large", 414 => "Request-URI Too Long", 415 => "Unsupported Media Type", 416 => "Requested Range Not Satisfiable", 417 => "Expectation Failed", 418 => "I'm a teapot", 419 => "Authentication Timeout", 420 => "Enhance Your Calm", 422 => "Unprocessable Entity", 423 => "Locked", 424 => "Failed Dependency", 424 => "Method Failure", 425 => "Unordered Collection", 426 => "Upgrade Required", 428 => "Precondition Required", 429 => "Too Many Requests", 431 => "Request Header Fields Too Large", 444 => "No Response", 449 => "Retry With", 450 => "Blocked by Windows Parental Controls", 451 => "Unavailable For Legal Reasons", 494 => "Request Header Too Large", 495 => "Cert Error", 496 => "No Cert", 497 => "HTTP to HTTPS", 499 => "Client Closed Request", 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", 507 => "Insufficient Storage", 508 => "Loop Detected", 509 => "Bandwidth Limit Exceeded", 510 => "Not Extended", 511 => "Network Authentication Required", 598 => "Network read timeout error", 599 => "Network connect timeout error");
?>

Source: Wikipedia "List_of_HTTP_status_codes"


viaujoc at videotron dot ca

2 years ago


Do not mix the use of http_response_code() and manually setting  the response code header because the actual HTTP status code being returned by the web server may not end up as expected. http_response_code() does not work if the response code has previously been set using the header() function. Example:

<?php
header
('HTTP/1.1 401 Unauthorized');
http_response_code(403);
print(
http_response_code());
?>

The raw HTTP response will be (notice the actual status code on the first line does not match the printed http_response_code in the body):

HTTP/1.1 401 Unauthorized
Date: Tue, 24 Nov 2020 13:49:08 GMT
Server: Apache
Connection: Upgrade, Keep-Alive
Keep-Alive: timeout=5, max=100
Transfer-Encoding: chunked
Content-Type: text/html; charset=UTF-8

403

I only tested it on Apache. I am not sure if this behavior is specific to Apache or common to all PHP distributions.


Anonymous

8 years ago


You can also create a enum by extending the SplEnum class.
<?php/** HTTP status codes */
class HttpStatusCode extends SplEnum {
    const
__default = self::OK;

        const

SWITCHING_PROTOCOLS = 101;
    const
OK = 200;
    const
CREATED = 201;
    const
ACCEPTED = 202;
    const
NONAUTHORITATIVE_INFORMATION = 203;
    const
NO_CONTENT = 204;
    const
RESET_CONTENT = 205;
    const
PARTIAL_CONTENT = 206;
    const
MULTIPLE_CHOICES = 300;
    const
MOVED_PERMANENTLY = 301;
    const
MOVED_TEMPORARILY = 302;
    const
SEE_OTHER = 303;
    const
NOT_MODIFIED = 304;
    const
USE_PROXY = 305;
    const
BAD_REQUEST = 400;
    const
UNAUTHORIZED = 401;
    const
PAYMENT_REQUIRED = 402;
    const
FORBIDDEN = 403;
    const
NOT_FOUND = 404;
    const
METHOD_NOT_ALLOWED = 405;
    const
NOT_ACCEPTABLE = 406;
    const
PROXY_AUTHENTICATION_REQUIRED = 407;
    const
REQUEST_TIMEOUT = 408;
    const
CONFLICT = 408;
    const
GONE = 410;
    const
LENGTH_REQUIRED = 411;
    const
PRECONDITION_FAILED = 412;
    const
REQUEST_ENTITY_TOO_LARGE = 413;
    const
REQUESTURI_TOO_LARGE = 414;
    const
UNSUPPORTED_MEDIA_TYPE = 415;
    const
REQUESTED_RANGE_NOT_SATISFIABLE = 416;
    const
EXPECTATION_FAILED = 417;
    const
IM_A_TEAPOT = 418;
    const
INTERNAL_SERVER_ERROR = 500;
    const
NOT_IMPLEMENTED = 501;
    const
BAD_GATEWAY = 502;
    const
SERVICE_UNAVAILABLE = 503;
    const
GATEWAY_TIMEOUT = 504;
    const
HTTP_VERSION_NOT_SUPPORTED = 505;
}


divinity76 at gmail dot com

2 years ago


if you need a response code not supported by http_response_code(), such as WebDAV / RFC4918's "HTTP 507 Insufficient Storage", try:

<?php
header
($_SERVER['SERVER_PROTOCOL'] . ' 507 Insufficient Storage');
?>
result: something like

HTTP/1.1 507 Insufficient Storage


Rob Zazueta

9 years ago


The note above from "Anonymous" is wrong. I'm running this behind the AWS Elastic Loadbalancer and trying the header(':'.$error_code...) method mentioned above is treated as invalid HTTP.

The documentation for the header() function has the right way to implement this if you're still on < php 5.4:

<?php
header
("HTTP/1.0 404 Not Found");
?>


Anonymous

10 years ago


If you don't have PHP 5.4 and want to change the returned status code, you can simply write:
<?php
header
(':', true, $statusCode);
?>

The ':' are mandatory, or it won't work

Richard F.

9 years ago


At least on my side with php-fpm and nginx this method does not change the text in the response, only the code.

<?php// HTTP/1.1 404 Not Found
http_response_code(404);?>

The resulting response is HTTP/1.1 404 OK


Steven

7 years ago


http_response_code is basically a shorthand way of writing a http status header, with the added bonus that PHP will work out a suitable Reason Phrase to provide by matching your response code to one of the values in an enumeration it maintains within php-src/main/http_status_codes.h. Note that this means your response code must match a response code that PHP knows about. You can't create your own response codes using this method, however you can using the header method.

In summary - The differences between "http_response_code" and "header" for setting response codes:

1. Using http_response_code will cause PHP to match and apply a Reason Phrase from a list of Reason Phrases that are hard-coded into the PHP source code.

2. Because of point 1 above, if you use http_response_code you must set a code that PHP knows about. You can't set your own custom code, however you can set a custom code (and Reason Phrase) if you use the header method.


stephen at bobs-bits dot com

8 years ago


It's not mentioned explicitly, but the return value when SETTING, is the OLD status code.
e.g.
<?php

$a

= http_response_code();
$b = http_response_code(202);
$c = http_response_code();var_dump($a, $b, $c);// Result:
// int(200)
// int(200)
// int(202)
?>

Anonymous

4 years ago


http_response_code() does not actually send HTTP headers, it only prepares the header list to be sent later on.
So you can call http_reponse_code() to set, get and reset the HTTP response code before it gets sent.

Test code:
<php
http_response_code(500);  // set the code
var_dump(headers_sent());  // check if headers are sent
http_response_code(200);  // avoid a default browser page


Chandra Nakka

5 years ago


On PHP 5.3 version, If you want to set HTTP response code. You can try this type of below trick :)

<?php

header

('Temporary-Header: True', true, 404);
header_remove('Temporary-Header');?>


yefremov {dot} sasha () gmail {dot} com

8 years ago


@craig at craigfrancis dot co dot uk@ wrote the function that replaces the original. It is very usefull, but has a bug. The original http_response_code always returns the previous or current code, not the code you are setting now. Here is my fixed version. I also use $GLOBALS to store the current code, but trigger_error() instead of exit. So now, how the function will behave in the case of error lies on the error handler. Or you can change it back to exit().

if (!function_exists('http_response_code')) {
    function http_response_code($code = NULL) {    
        $prev_code = (isset($GLOBALS['http_response_code']) ? $GLOBALS['http_response_code'] : 200);

        if ($code === NULL) {
            return $prev_code;
        }

        switch ($code) {
            case 100: $text = 'Continue'; break;
            case 101: $text = 'Switching Protocols'; break;
            case 200: $text = 'OK'; break;
            case 201: $text = 'Created'; break;
            case 202: $text = 'Accepted'; break;
            case 203: $text = 'Non-Authoritative Information'; break;
            case 204: $text = 'No Content'; break;
            case 205: $text = 'Reset Content'; break;
            case 206: $text = 'Partial Content'; break;
            case 300: $text = 'Multiple Choices'; break;
            case 301: $text = 'Moved Permanently'; break;
            case 302: $text = 'Moved Temporarily'; break;
            case 303: $text = 'See Other'; break;
            case 304: $text = 'Not Modified'; break;
            case 305: $text = 'Use Proxy'; break;
            case 400: $text = 'Bad Request'; break;
            case 401: $text = 'Unauthorized'; break;
            case 402: $text = 'Payment Required'; break;
            case 403: $text = 'Forbidden'; break;
            case 404: $text = 'Not Found'; break;
            case 405: $text = 'Method Not Allowed'; break;
            case 406: $text = 'Not Acceptable'; break;
            case 407: $text = 'Proxy Authentication Required'; break;
            case 408: $text = 'Request Time-out'; break;
            case 409: $text = 'Conflict'; break;
            case 410: $text = 'Gone'; break;
            case 411: $text = 'Length Required'; break;
            case 412: $text = 'Precondition Failed'; break;
            case 413: $text = 'Request Entity Too Large'; break;
            case 414: $text = 'Request-URI Too Large'; break;
            case 415: $text = 'Unsupported Media Type'; break;
            case 500: $text = 'Internal Server Error'; break;
            case 501: $text = 'Not Implemented'; break;
            case 502: $text = 'Bad Gateway'; break;
            case 503: $text = 'Service Unavailable'; break;
            case 504: $text = 'Gateway Time-out'; break;
            case 505: $text = 'HTTP Version not supported'; break;
            default:
                trigger_error('Unknown http status code ' . $code, E_USER_ERROR); // exit('Unknown http status code "' . htmlentities($code) . '"');
                return $prev_code;
        }

        $protocol = (isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0');
        header($protocol . ' ' . $code . ' ' . $text);
        $GLOBALS['http_response_code'] = $code;

        // original function always returns the previous or current code
        return $prev_code;
    }
}


Kubo2

6 years ago


If you want to set a HTTP response code without the need of specifying a protocol version, you can actually do it without http_response_code():

<?php

header

('Status: 404', TRUE, 404);?>


zweibieren at yahoo dot com

7 years ago


The limited list given by Stefan W is out of date. I have just tested 301 and 302 and both work.

divinity76 at gmail dot com

6 years ago


warning, it does not check if headers are already sent (if it is, it won't *actually* change the code, but a subsequent call will imply that it did!!),

you might wanna do something like
function ehttp_response_code(int $response_code = NULL): int {
    if ($response_code === NULL) {
        return http_response_code();
    }
    if (headers_sent()) {
        throw new Exception('tried to change http response code after sending headers!');
    }
    return http_response_code($response_code);
}


PHP фатальные ошибки возвращаются в качестве кода состояния 200 для HTTP-клиента. Как я могу заставить его вернуть код состояния 500 (Внутренняя ошибка сервера)?

 header("HTTP/1.1 500 Internal Server Error"); 

Это именно та проблема, с которой я вчера столкнулся, и нашел решение следующим образом:

1) прежде всего, вам нужно уловить PHP фатальные ошибки, которые являются ошибкой E_ERROR. при возникновении этой ошибки скрипт будет хранить ошибку и прекратить выполнение. вы можете получить сохраненную ошибку, вызвав функцию error_get_last ().

2) до завершения сценария всегда будет вызываться функция обратного вызова register_shutdown_function (). поэтому вам необходимо зарегистрировать обработчик ошибок с помощью этой функции, чтобы сделать то, что вы хотите, в этом случае вернуть заголовок 500 и настроенную внутреннюю страницу ошибок (необязательно).

 function my_error_handler() { $last_error = error_get_last(); if ($last_error && $last_error['type']==E_ERROR) { header("HTTP/1.1 500 Internal Server Error"); echo '...';//html for 500 page } } register_shutdown_function('my_error_handler'); 

Примечание. Если вы хотите поймать собственный тип ошибки, который начинается с E_USER *, вы можете использовать функцию set_error_handler () для регистрации обработчика ошибок и запускать ошибку с помощью функции trigger_error, однако этот обработчик ошибок не может обрабатывать тип ошибки E_ERROR. см. объяснение на php.net о обработчике ошибок

Я использовал «set_exception_handler» для обработки исключений uncaught.

 function handleException($ex) { error_log("Uncaught exception class=" . get_class($ex) . " message=" . $ex->getMessage() . " line=" . $ex->getLine()); ob_end_clean(); # try to purge content sent so far header('HTTP/1.1 500 Internal Server Error'); echo 'Internal error'; } set_exception_handler('handleException'); 

Невозможно обрабатывать PHP E_ERROR каким-либо образом в соответствии с документацией PHP: http://www.php.net/manual/en/function.set-error-handler.php

Также нельзя обрабатывать «E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING и большую часть E_STRICT» в соответствии с этой ссылкой.

Вы можете предоставить обработчик для другой ошибки, предупреждения и уведомлений, включая E_USER_ERROR, но это действительно не так полезно, как кажется, поскольку эта ошибка только умышленно бросается программистом с помощью trigger_error ().

И, конечно же, вы можете поймать любое исключение (даже те, которые бросают собственные PHP-функции).

Я согласен, что это проблема. Серверы НЕ должны возвращать 200 OK, когда код приложения сбой и ожоги.

Вам придется поймать заброшенную ошибку с помощью try / catch, а затем использовать этот блок catch для отправки заголовка () с ошибкой 500.

 try { ...badcode... throw new Exception('error'); } catch (Exception $e) { header("Status: 500 Server Error"); var_dump($e->getMessage()); } 

Если фатальное исключение не окружено блоками try {} catch, вы должны зарегистрировать глобальный обработчик и использовать register_shutdown_function() чтобы проверить наличие ошибки на конце скрипта.

Никогда не забудьте установить header("HTTP/1.1 200 OK", true, 200); как последняя строка любого пути выполнения:

 //first things first: header("HTTP/1.1 500 Internal Server Error", true, 500); //Application code, includes, requires, etc. [...] //somewhere something happens //die(); throw new Exception("Uncaught exception!"); //last things last, only reached if code execution was not stopped by uncaught exception or some fatal error header("HTTP/1.1 200 OK", true, 200); 

В PHP 5.4 вы можете заменить вышеописанную функцию header гораздо лучше http_response_code(200) или http_response_code(500) .

Трудная вещь при работе с фатальными ошибками (ошибки компиляции, например отсутствующая точка с запятой) заключается в том, что сценарий не будет выполнен, поэтому он не поможет установить код состояния в этом скрипте. Однако, когда вы включаете или требуете сценарий, исполняемый скрипт будет выполнен независимо от ошибок во включенном скрипте. При этом я прихожу к этому решению:

рок-твердое тело-script.php:

 // minimize changes to this script to keep it rock-solid http_response_code(500); // PHP >= 5.4 require_once("script-i-want-to-guard-for-errors.php"); 

скрипт-я-хочу-к-охранником-для-errors.php:

 // do all the processsing // don't produce any output // you might want to use output buffering http_response_code(200); // PHP >= 5.4 // here you can produce the output 

Направьте свой звонок на rock-solid-script.php, и вы готовы к работе.

Мне бы лучше было установить код состояния по умолчанию на 500 в .htaccess. Это кажется мне более элегантным, но я не могу найти способ его снять. Я попробовал флаг RewriteRule R, но это предотвращает выполнение php вообще, так что это бесполезно.

Стандартная конфигурация PHP возвращает 500 при возникновении ошибки! Просто убедитесь, что ваш display_errors = выключен. Вы можете имитировать его с помощью:

 ini_set('display_errors', 0); noFunction(); 

По умолчанию директива display_errors отключена по умолчанию.

Страницу с кодом ответа 500 веб-сервер возвращает, когда не может обработать запрос из-за ошибок в файлах сайта.

Внешний вид ошибки 500 зависит от того, чем она вызвана. При неполадках в скриптах сайта отобразится пустая страница, сообщение HTTP ERROR 500 или текст обработчика PHP.

Если проблема в файле .htaccess — сообщение Internal Server Error.

Часто ошибку 500 можно легко устранить даже не имея знаний в области веб-разработки. О том, как это сделать, расскажем далее.

Ошибки в файле .htaccess

Сообщение Internal Server Error выводится, когда в файле .htaccess есть ошибки. Переименуйте файл .htaccess и проверьте корректность работы сайта. Если он доступен, удалите правила, которые были добавлены последними, или восстановите старый файл из резервной копии.

Ошибки в скриптах сайта

Пустая страница — не всегда признак ошибки 500. Поэтому в первую очередь узнайте код ответа, с которым она открывается. Это можно сделать при помощи инструментов разработчика в браузерах.

Инструменты разработчика — функция для исследования работы сайта. Она позволяет узнать время ответа сервера, код ответа, посмотреть текст возникших ошибок и многое другое.

Нажмите сочетание клавиш Ctrl+Shift+I или используйте меню браузера:

  • Mozilla Firefox — «Веб-разработка» → «Инструменты разработчика»;
  • Google Chrome — «Дополнительные инструменты» → «Инструменты разработчика»;
  • Opera — «Разработка» → «Инструменты разработчика».

Перейдите во вкладку «Сеть (Network)». На ошибку 500 указывает соответствующее число в колонке «Статус».

Статус пустой страницы может быть и 200 (Ok). В таком случае проверьте, есть ли содержимое в индексном файле сайта, очистите кеш вашей CMS. Если ранее сайт работал корректно, восстановите его из резервной копии.

Вывод ошибок на сайте

Вывод ошибок PHP на хостинге по умолчанию выключен. Чтобы увидеть их текст, добавьте в файл .htaccess правило: php_value display_errors 1 и обновите страницу сайта.

Если текст не отобразился, включите вывод ошибок через конфигурационный файл CMS. Он расположен в корневой директории сайта.

WordPress

Замените в файле wp-config.php строку define(‘WP_DEBUG’, false); на define(‘WP_DEBUG’, true);

Joomla

Измените значение переменных debug и error_reporting в configuration.php на: public $debug = '1'; и public $error_reporting = 'maximum';

1С-Битрикс

В конфигурационном файле по пути ~/public_html/bitrix/php_interface/dbconn.php замените значение переменных DBDebug и DBDebugToFile на: $DBDebug = true; и $DBDebugToFile = true;

Laravel

В файле .env измените APP_DEBUG=false на APP_DEBUG=true

Алгоритм устранения ошибки можно найти в интернете, поместив ее текст в строку любой поисковой системы. Если с помощью найденной информации возобновить работу сайта не получится, восстановите его из резервной копии. Наши специалисты могут помочь с восстановлением. Для этого направьте обращение из раздела «Поддержка» Панели управления.

Журнал ошибок PHP

Иногда ошибка не выводится на странице или возникает периодически: ее тяжело отследить. Чтобы узнать текст таких ошибок, записывайте информацию о них в файл — журнал ошибок PHP. Подключите его, добавив в .htaccess строку: php_value error_log /home/username/domains/domain.ru/php_errors.log и обновите страницу сайта.

Откройте создавшийся файл журнала с помощью Файлового менеджера в Панели управления. Чтобы просматривать возникающие ошибки в реальном времени, отметьте опцию «Включить автообновление».

Быстро возобновить работу сайта можно, восстановив его из резервной копии за дату, когда ошибок не было. Если восстановление нежелательно, обратитесь к разработчику.

Для устранения некоторых ошибок не требуется специальных знаний. Рассмотрим самые распространенные.

Нехватка оперативной памяти

Ошибка с текстом Allowed memory size возникает из-за нехватки оперативной памяти для выполнения скрипта: PHP Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 81 bytes) in /home/username/domains/domain.ru/public_html/somescript.php

Чтобы исправить ее, увеличьте лимит оперативной памяти, добавив в файл .htaccess директиву:

php_value memory_limit 512M

Вместо «512» укажите необходимый объем памяти. Максимальное значение ограничивается тарифом.

Текст Out of memory означает, что достигнут лимит оперативной памяти по тарифному плану:

PHP Fatal error: Out of memory (allocated 39059456) (tried to allocate 262144 bytes) in /home/username/domains/domain.ru/public_html/somescript.php

Оптимизируйте работу скриптов, чтобы они потребляли меньше памяти. Объемную загрузку или выгрузку данных производите частями. Если оптимизацию произвести невозможно, измените тариф на тот, по которому предоставляется достаточно памяти для комфортной работы сайта.

Ошибки в CMS

При обновлении CMS случаются синтаксические ошибки:

PHP Parse error: syntax error, unexpected '[', expecting ')' in /home/username/domains/domain.ru/public_html/wp-content/plugins/wordpress-23-related-posts-plugin/config.php on line 130

Это происходит из-за того, что новые функции CMS не поддерживают устаревшие версии PHP. Чтобы исправить ошибку, измените версию PHP для сайта на более современную в разделе «Сайты» → «Веб-серверы».

Если предыдущая рекомендация не помогла, обратите внимание на путь до неработающего скрипта: там может быть указан каталог плагина или темы. Чтобы исправить ошибку, отключите их. Для этого переименуйте папку, в которой они расположены. После устранения ошибки авторизуйтесь в административной части сайта и измените тему или переустановите плагин.

Чтобы исправить большинство ошибок PHP, достаточно изучить их текст и принять меры, указанные в статье. Если вам не удается справиться с ней самостоятельно, обратитесь в службу поддержки.

Была ли эта инструкция полезной?

Антон Шевчук // Web-разработчик

Не совершает ошибок только тот, кто ничего не делает, и мы тому пример – трудимся не покладая рук над созданием рабочих мест для тестировщиков 🙂

О да, в этой статье я поведу свой рассказа об ошибках в PHP, и том как их обуздать.

Ошибки

Разновидности в семействе ошибок

Перед тем как приручать ошибки, я бы рекомендовал изучить каждый вид и отдельно обратить внимание на самых ярких представителей.

Чтобы ни одна ошибка не ушла незамеченной потребуется включить отслеживание всех ошибок с помощью функции error_reporting(), а с помощью директивы display_errors включить их отображение:

<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);

Фатальные ошибки

Самый грозный вид ошибок – фатальные, они могут возникнуть как при компиляции, так и при работе парсера или PHP-скрипта, выполнение скрипта при этом прерывается.

E_PARSE
Это ошибка появляется, когда вы допускаете грубую ошибку синтаксиса и интерпретатор PHP не понимает, что вы от него хотите, например если не закрыли фигурную или круглую скобочку:

<?php
/**
 Parse error: syntax error, unexpected end of file
 */
{

Или написали на непонятном языке:

<?php
/**
 Parse error: syntax error, unexpected '...' (T_STRING)
 */
Тут будет ошибка парсера

Лишние скобочки тоже встречаются, и не важно круглые либо фигурные:

<?php
/**
 Parse error: syntax error, unexpected '}'
 */
}

Отмечу один важный момент – код файла, в котором вы допустили parse error не будет выполнен, следовательно, если вы попытаетесь включить отображение ошибок в том же файле, где возникла ошибка парсера то это не сработает:

<?php
// этот код не сработает
error_reporting(E_ALL);
ini_set('display_errors', 1);

// т.к. вот тут
ошибка парсера

E_ERROR
Это ошибка появляется, когда PHP понял что вы хотите, но сделать сие не получилось ввиду ряда причин, так же прерывает выполнение скрипта, при этом код до появления ошибки сработает:

Не был найден подключаемый файл:

/**
 Fatal error: require_once(): Failed opening required 'not-exists.php' (include_path='.:/usr/share/php:/usr/share/pear')
 */
require_once 'not-exists.php';

Было брошено исключение (что это за зверь, расскажу немного погодя), но не было обработано:

/**
 Fatal error: Uncaught exception 'Exception'
 */
throw new Exception();

При попытке вызвать несуществующий метод класса:

/**
 Fatal error: Call to undefined method stdClass::notExists()
 */
$stdClass = new stdClass();
$stdClass->notExists();

Отсутствия свободной памяти (больше, чем прописано в директиве memory_limit) или ещё чего-нить подобного:

/**
 Fatal Error: Allowed Memory Size
 */
$arr = array();

while (true) {
    $arr[] = str_pad(' ', 1024);
}

Очень часто происходит при чтении либо загрузки больших файлов, так что будьте внимательны с вопросом потребляемой памяти

Рекурсивный вызов функции. В данном примере он закончился на 256-ой итерации, ибо так прописано в настройках xdebug:

/**
 Fatal error: Maximum function nesting level of '256' reached, aborting!
 */
function deep() {
    deep();
}
deep();

Не фатальные

Данный вид не прерывает выполнение скрипта, но именно их обычно находит тестировщик, и именно они доставляют больше всего хлопот у начинающих разработчиков.

E_WARNING
Частенько встречается, когда подключаешь файл с использованием include, а его не оказывается на сервере или ошиблись указывая путь к файлу:

/**
 Warning: include_once(): Failed opening 'not-exists.php' for inclusion
 */
include_once 'not-exists.php';

Бывает, если используешь неправильный тип аргументов при вызове функций:

/**
 Warning: join(): Invalid arguments passed
 */
join('string', 'string');

Их очень много, и перечислять все не имеет смысла…

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

Когда обращаются к неопределенной переменной:

/**
 Notice: Undefined variable: a
 */
echo $a;

Когда обращаются к несуществующему элементу массива:

<?php
/**
 Notice: Undefined index: a
 */
$b = array();
$b['a'];

Когда обращаются к несуществующей константе:

/**
 Notice: Use of undefined constant UNKNOWN_CONSTANT - assumed 'UNKNOWN_CONSTANT'
 */
echo UNKNOWN_CONSTANT;

Когда не конвертируют типы данных:

/**
 Notice: Array to string conversion
 */
echo array();

Для избежания подобных ошибок – будьте внимательней, и если вам IDE подсказывает о чём-то – не игнорируйте её:

PHP E_NOTICE in PHPStorm

E_STRICT
Это ошибки, которые научат вас писать код правильно, чтобы не было стыдно, тем более IDE вам эти ошибки сразу показывают. Вот например, если вызвали не статический метод как статику, то код будет работать, но это как-то неправильно, и возможно появление серьёзных ошибок, если в дальнейшем метод класса будет изменён, и появится обращение к $this:

/**
 Strict standards: Non-static method Strict::test() should not be called statically
 */
class Strict { 
    public function test() { 
        echo 'Test'; 
    } 
}

Strict::test();

E_DEPRECATED
Так PHP будет ругаться, если вы используете устаревшие функции (т.е. те, что помечены как deprecated, и в следующем мажорном релизе их не будет):

/**
 Deprecated: Function split() is deprecated
 */

// популярная функция, всё никак не удалят из PHP
// deprecated since 5.3
split(',', 'a,b');

В моём редакторе подобные функции будут зачёркнуты:

PHP E_DEPRECATED in PHPStorm

Обрабатываемые

Этот вид, которые разводит сам разработчик кода, я их уже давно не встречал, не рекомендую их вам заводить:

  • E_USER_ERROR – критическая ошибка
  • E_USER_WARNING – не критическая ошибка
  • E_USER_NOTICE – сообщения которые не являются ошибками

Отдельно стоит отметить E_USER_DEPRECATED – этот вид всё ещё используется очень часто для того, чтобы напомнить программисту, что метод или функция устарели и пора переписать код без использования оной. Для создания этой и подобных ошибок используется функция trigger_error():

/**
 * @deprecated Deprecated since version 1.2, to be removed in 2.0
 */
function generateToken() {
    trigger_error('Function `generateToken` is deprecated, use class `Token` instead', E_USER_DEPRECATED);
    // ...
    // code ...
    // ...
}

Теперь, когда вы познакомились с большинством видов и типов ошибок, пора озвучить небольшое пояснение по работе директивы display_errors:

  • если display_errors = on, то в случае ошибки браузер получит html c текстом ошибки и кодом 200
  • если же display_errors = off, то для фатальных ошибок код ответа будет 500 и результат не будет возвращён пользователю, для остальных ошибок – код будет работать неправильно, но никому об этом не расскажет

Приручение

Для работы с ошибками в PHP существует 3 функции:

  • set_error_handler() — устанавливает обработчик для ошибок, которые не обрывают работу скрипта (т.е. для не фатальных ошибок)
  • error_get_last() — получает информацию о последней ошибке
  • register_shutdown_function() — регистрирует обработчик который будет запущен при завершении работы скрипта. Данная функция не относится непосредственно к обработчикам ошибок, но зачастую используется именно для этого

Теперь немного подробностей об обработке ошибок с использованием set_error_handler(), в качестве аргументов данная функция принимает имя функции, на которую будет возложена миссия по обработке ошибок и типы ошибок которые будут отслеживаться. Обработчиком ошибок может так же быть методом класса, или анонимной функцией, главное, чтобы он принимал следующий список аргументов:

  • $errno – первый аргумент содержит тип ошибки в виде целого числа
  • $errstr – второй аргумент содержит сообщение об ошибке
  • $errfile – необязательный третий аргумент содержит имя файла, в котором произошла ошибка
  • $errline – необязательный четвертый аргумент содержит номер строки, в которой произошла ошибка
  • $errcontext – необязательный пятый аргумент содержит массив всех переменных, существующих в области видимости, где произошла ошибка

В случае если обработчик вернул true, то ошибка будет считаться обработанной и выполнение скрипта продолжится, иначе — будет вызван стандартный обработчик, который логирует ошибку и в зависимости от её типа продолжит выполнение скрипта или завершит его. Вот пример обработчика:

<?php
    // включаем отображение всех ошибок, кроме E_NOTICE
    error_reporting(E_ALL & ~E_NOTICE);
    ini_set('display_errors', 1);
    
    // наш обработчик ошибок
    function myHandler($level, $message, $file, $line, $context) {
        // в зависимости от типа ошибки формируем заголовок сообщения
        switch ($level) {
            case E_WARNING:
                $type = 'Warning';
                break;
            case E_NOTICE:
                $type = 'Notice';
                break;
            default;
                // это не E_WARNING и не E_NOTICE
                // значит мы прекращаем обработку ошибки
                // далее обработка ложится на сам PHP
                return false;
        }
        // выводим текст ошибки
        echo "<h2>$type: $message</h2>";
        echo "<p><strong>File</strong>: $file:$line</p>";
        echo "<p><strong>Context</strong>: $". join(', $', array_keys($context))."</p>";
        // сообщаем, что мы обработали ошибку, и дальнейшая обработка не требуется
        return true;
    }
    
    // регистрируем наш обработчик, он будет срабатывать на для всех типов ошибок
    set_error_handler('myHandler', E_ALL);

У вас не получится назначить более одной функции для обработки ошибок, хотя очень бы хотелось регистрировать для каждого типа ошибок свой обработчик, но нет – пишите один обработчик, и всю логику отображения для каждого типа описывайте уже непосредственно в нём

С обработчиком, который написан выше есть одна существенная проблема – он не ловит фатальные ошибки, и вместо сайта пользователи увидят лишь пустую страницу, либо, что ещё хуже, сообщение об ошибке. Дабы не допустить подобного сценария следует воспользоваться функцией register_shutdown_function() и с её помощью зарегистрировать функцию, которая всегда будет выполняться по окончанию работы скрипта:

function shutdown() {
    echo 'Этот текст будет всегда отображаться';
}
register_shutdown_function('shutdown');

Данная функция будет срабатывать всегда!

Но вернёмся к ошибкам, для отслеживания появления в коде ошибки воспользуемся функцией error_get_last(), с её помощью можно получить информацию о последней выявленной ошибке, а поскольку фатальные ошибки прерывают выполнение кода, то они всегда будут выполнять роль “последних”:

function shutdown() {
    $error = error_get_last();
    if (
        // если в коде была допущена ошибка
        is_array($error) &&
        // и это одна из фатальных ошибок
        in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])
    ) {
        // очищаем буфер вывода (о нём мы ещё поговорим в последующих статьях)
        while (ob_get_level()) {
            ob_end_clean();
        }
        // выводим описание проблемы
        echo 'Сервер находится на техническом обслуживании, зайдите позже';
    }
}
register_shutdown_function('shutdown');

Задание
Дополнить обработчик фатальных ошибок выводом исходного кода файла где была допущена ошибка, а так же добавьте подсветку синтаксиса выводимого кода.

О прожорливости

Проведём простой тест, и выясним – сколько драгоценных ресурсов кушает самая тривиальная ошибка:

/**
 * Этот код не вызывает ошибок
 */

// сохраняем параметры памяти и времени выполнения скрипта
$memory = memory_get_usage();
$time= microtime(true);

$a = '';
$arr = [];
for ($i = 0; $i < 10000; $i++) {
    $arr[$a] = $i;
}

printf('%f seconds <br/>', microtime(true) - $time);
echo number_format(memory_get_usage() - $memory, 0, '.', ' '), ' bytes<br/>';

В результате запуска данного скрипта у меня получился вот такой результат:

0.002867 seconds 
984 bytes

Теперь добавим ошибку в цикле:

/**
 * Этот код содержит ошибку
 */

// сохраняем параметры памяти и времени выполнения скрипта
$memory = memory_get_usage();
$time= microtime(true);

$a = '';
$arr = [];
for ($i = 0; $i < 10000; $i++) {
    $arr[$b] = $i; // тут ошиблись с именем переменной
}

printf('%f seconds <br/>', microtime(true) - $time);
echo number_format(memory_get_usage() - $memory, 0, '.', ' '), ' bytes<br/>';

Результат ожидаемо хуже, и на порядок (даже на два порядка!):

0.263645 seconds 
992 bytes

Вывод однозначен – ошибки в коде приводят к лишней прожорливости скриптов – так что во время разработки и тестирования приложения включайте отображение всех ошибок!

Тестирование проводил на PHP версии 5.6, в седьмой версии результат лучше – 0.0004 секунды против 0.0050 – разница только на один порядок, но в любом случае результат стоит прикладываемых усилий по исправлению ошибок

Где собака зарыта

В PHP есть спец символ «@» – оператор подавления ошибок, его используют дабы не писать обработку ошибок, а положится на корректное поведение PHP в случае чего:

<?php
    echo @UNKNOWN_CONSTANT;

При этом обработчик ошибок указанный в set_error_handler() всё равно будет вызван, а факт того, что к ошибке было применено подавление можно отследить вызвав функцию error_reporting() внутри обработчика, в этом случае она вернёт 0.

Если вы в такой способ подавляете ошибки, то это уменьшает нагрузку на процессор в сравнении с тем, если вы их просто скрываете (см. сравнительный тест выше), но в любом случае, подавление ошибок это зло

Исключения

В эру PHP4 не было исключений (exceptions), всё было намного сложнее, и разработчики боролись с ошибками как могли, это было сражение не на жизнь, а на смерть… Окунуться в эту увлекательную историю противостояния можете в статье Исключительный код. Часть 1. Стоит ли её читать сейчас? Думаю да, ведь это поможет вам понять эволюцию языка, и раскроет всю прелесть исключений

Исключения — исключительные событие в PHP, в отличии от ошибок не просто констатируют наличие проблемы, а требуют от программиста дополнительных действий по обработке каждого конкретного случая.

К примеру, скрипт должен сохранить какие-то данные в кеш файл, если что-то пошло не так (нет доступа на запись, нет места на диске), генерируется исключение соответствующего типа, а в обработчике исключений принимается решение – сохранить в другое место или сообщить пользователю о проблеме.

Исключение – это объект который наследуется от класса Exception, содержит текст ошибки, статус, а также может содержать ссылку на другое исключение которое стало первопричиной данного. Модель исключений в PHP схожа с используемыми в других языках программирования. Исключение можно инициировать (как говорят, “бросить”) при помощи оператора throw, и можно перехватить (“поймать”) оператором catch. Код генерирующий исключение, должен быть окружен блоком try, для того чтобы можно было перехватить исключение. Каждый блок try должен иметь как минимум один соответствующий ему блок catch или finally:

try {
    // код который может выбросить исключение
    if (rand(0, 1)) {
        throw new Exception('One')
    } else {
        echo 'Zero';
    }
} catch (Exception $e) {
    // код который может обработать исключение
    echo $e->getMessage();
}

В каких случаях стоит применять исключения:

  • если в рамках одного метода/функции происходит несколько операций которые могут завершиться неудачей
  • если используемый вами фреймверк или библиотека декларируют их использование

Для иллюстрации первого сценария возьмём уже озвученный пример функции для записи данных в файл – помешать нам может очень много факторов, а для того, чтобы сообщить выше стоящему коду в чем именно была проблема необходимо создать и выбросить исключение:

$directory = __DIR__ . DIRECTORY_SEPARATOR . 'logs';

// директории может не быть
if (!is_dir($directory)) {
    throw new Exception('Directory `logs` is not exists');
}

// может не быть прав на запись в директорию
if (!is_writable($directory)) {
    throw new Exception('Directory `logs` is not writable');
}

// возможно кто-то уже создал файл, и закрыл к нему доступ
if (!$file = @fopen($directory . DIRECTORY_SEPARATOR . date('Y-m-d') . '.log', 'a+')) {
    throw new Exception('System can't create log file');
}

fputs($file, date('[H:i:s]') . " donen");
fclose($file);

Соответственно ловить данные исключения будем примерно так:

try {
    // код который пишет в файл
    // ...
} catch (Exception $e) {
    // выводим текст ошибки
    echo 'Не получилось: '. $e->getMessage();
}

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

// исключения файловой системы
class FileSystemException extends Exception {}

// исключения связанные с директориями
class DirectoryException extends FileSystemException {
    // коды исключений
    const DIRECTORY_NOT_EXISTS =  1;
    const DIRECTORY_NOT_WRITABLE = 2;
}

// исключения связанные с файлами
class FileException extends FileSystemException {}

Теперь, если использовать эти исключения то можно получить следующий код:

try {
    // код который пишет в файл
    if (!is_dir($directory)) {
        throw new DirectoryException('Directory `logs` is not exists', DirectoryException::DIRECTORY_NOT_EXISTS);
    }

    if (!is_writable($directory)) {
        throw new DirectoryException('Directory `logs` is not writable', DirectoryException::DIRECTORY_NOT_WRITABLE);
    }

    if (!$file = @fopen($directory . DIRECTORY_SEPARATOR . date('Y-m-d') . '.log', 'a+')) {
        throw new FileException('System can't open log file');
    }

    fputs($file, date('[H:i:s]'') . " donen");
    fclose($file);
} catch (DirectoryException $e) {
    echo 'С директорией возникла проблема: '. $e->getMessage();
} catch (FileException $e) {
    echo 'С файлом возникла проблема: '. $e->getMessage();
} catch (FileSystemException $e) {
    echo 'Ошибка файловой системы: '. $e->getMessage();
} catch (Exception $e) {
    echo 'Ошибка сервера: '. $e->getMessage();
}

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

Так, а что будет если не поймать исключение? Вы получите “Fatal Error: Uncaught exception …”. Неприятно.
Чтобы избежать подобной ситуации следует использовать функцию set_exception_handler() и установить обработчик для исключений, которые брошены вне блока try-catch и не были обработаны. После вызова такого обработчика выполнение скрипта будет остановлено:

// в качестве обработчика событий 
// будем использовать анонимную функцию
set_exception_handler(function($exception) {
    /** @var Exception $exception */
    echo $exception->getMessage(), "<br/>n";
    echo $exception->getFile(), ':', $exception->getLine(), "<br/>n";
    echo $exception->getTraceAsString(), "<br/>n";
});

Ещё расскажу про конструкцию с использованием блока finally – этот блок будет выполнен вне зависимости от того, было выброшено исключение или нет:

try {
    // код который может выбросить исключение
} catch (Exception $e) {
    // код который может обработать исключение
    // если конечно оно появится
} finally {
    // код, который будет выполнен при любом раскладе
}

Для понимания того, что это нам даёт приведу следующий пример использования блока finally:

try {
    // где-то глубоко внутри кода
    // соединение с базой данных
    $handler = mysqli_connect('localhost', 'root', '', 'test');

    try {
        // при работе с БД возникла исключительная ситуация
        // ...
        throw new Exception('DB error');
    } catch (Exception $e) {
        // исключение поймали, обработали на своём уровне
        // и должны его пробросить вверх, для дальнейшей обработки
        throw new Exception('Catch exception', 0, $e);
    } finally {
        // но, соединение с БД необходимо закрыть
        // будем делать это в блоке finally
        mysqli_close($handler);
    }

    // этот код не будет выполнен, если произойдёт исключение в коде выше
    echo "Ok";
} catch (Exception $e) {
    // ловим исключение, и выводим текст
    echo $e->getMessage();
    echo "<br/>";
    // выводим информацию о первоначальном исключении
    echo $e->getPrevious()->getMessage();
}

Т.е. запомните – блок finally будет выполнен даже в том случае, если вы в блоке catch пробрасываете исключение выше (собственно именно так он и задумывался).

Для вводной статьи информации в самый раз, кто жаждет ещё подробностей, то вы их найдёте в статье Исключительный код 😉

Задание
Написать свой обработчик исключений, с выводом текста файла где произошла ошибка, и всё это с подсветкой синтаксиса, так же не забудьте вывести trace в читаемом виде. Для ориентира – посмотрите как это круто выглядит у whoops.

PHP7 – всё не так, как было раньше

Так, вот вы сейчас всю информацию выше усвоили и теперь я буду грузить вас нововведениями в PHP7, т.е. я буду рассказывать о том, с чем вы столкнётесь через год работы PHP разработчиком. Ранее я вам рассказывал и показывал на примерах какой костыль нужно соорудить, чтобы отлавливать критические ошибки, так вот – в PHP7 это решили исправить, но как обычно завязались на обратную совместимость кода, и получили хоть и универсальное решение, но оно далеко от идеала. А теперь по пунктам об изменениях:

  1. при возникновении фатальных ошибок типа E_ERROR или фатальных ошибок с возможностью обработки E_RECOVERABLE_ERROR PHP выбрасывает исключение
  2. эти исключения не наследуют класс Exception (помните я говорил об обратной совместимости, это всё ради неё)
  3. эти исключения наследуют класс Error
  4. оба класса Exception и Error реализуют интерфейс Throwable
  5. вы не можете реализовать интерфейс Throwable в своём коде

Интерфейс Throwable практически полностью повторяет нам Exception:

interface Throwable
{
    public function getMessage(): string;
    public function getCode(): int;
    public function getFile(): string;
    public function getLine(): int;
    public function getTrace(): array;
    public function getTraceAsString(): string;
    public function getPrevious(): Throwable;
    public function __toString(): string;
}

Сложно? Теперь на примерах, возьмём те, что были выше и слегка модернизируем:

try {
    // файл, который вызывает ошибку парсера
    include 'e_parse_include.php';
} catch (Error $e) {
    var_dump($e);
}

В результате ошибку поймаем и выведем:

object(ParseError)#1 (7) {
  ["message":protected] => string(48) "syntax error, unexpected 'будет' (T_STRING)"
  ["string":"Error":private] => string(0) ""
  ["code":protected] => int(0)
  ["file":protected] => string(49) "/www/education/error/e_parse_include.php"
  ["line":protected] => int(4)
  ["trace":"Error":private] => array(0) { }
  ["previous":"Error":private] => NULL
}

Как видите – поймали исключение ParseError, которое является наследником исключения Error, который реализует интерфейс Throwable, в доме который построил Джек. Ещё есть другие, но не буду мучать – для наглядности приведу иерархию исключений:

interface Throwable
  |- Exception implements Throwable
  |    |- ErrorException extends Exception
  |    |- ... extends Exception
  |    `- ... extends Exception
  `- Error implements Throwable
      |- TypeError extends Error
      |- ParseError extends Error
      |- ArithmeticError extends Error
      |  `- DivisionByZeroError extends ArithmeticError
      `- AssertionError extends Error 

TypeError – для ошибок, когда тип аргументов функции не совпадает с передаваемым типом:

try {
    (function(int $one, int $two) {
        return;
    })('one', 'two');
} catch (TypeError $e) {
    echo $e->getMessage();
}

ArithmeticError – могут возникнуть при математических операциях, к примеру когда результат вычисления превышает лимит выделенный для целого числа:

try {
    1 << -1;
} catch (ArithmeticError $e) {
    echo $e->getMessage();
}

DivisionByZeroError – ошибка деления на ноль:

try {
    1 / 0;
} catch (ArithmeticError $e) {
    echo $e->getMessage();
}

AssertionError – редкий зверь, появляется когда условие заданное в assert() не выполняется:

ini_set('zend.assertions', 1);
ini_set('assert.exception', 1);

try {
    assert(1 === 0);
} catch (AssertionError $e) {
    echo $e->getMessage();
}

При настройках production-серверов, директивы zend.assertions и assert.exception отключают, и это правильно

Задание
Написать универсальный обработчик ошибок для PHP7, который будет отлавливать все возможные исключения.

При написании данного раздела были использованы материалы из статьи Throwable Exceptions and Errors in PHP 7

Отладка

Иногда для отладки кода нужно отследить что происходило с переменной или объектом на определённом этапе, для этих целей есть функция debug_backtrace() и debug_print_backtrace() которые вернут историю вызовов функций/методов в обратном порядке:

<?php
function example() {
    echo '<pre>';
    debug_print_backtrace();
    echo '</pre>';
}

class ExampleClass {
    public static function method () {
        example();
    }
}

ExampleClass::method();

В результате выполнения функции debug_print_backtrace() будет выведен список вызовов приведших нас к данной точке:

#0  example() called at [/www/education/error/backtrace.php:10]
#1  ExampleClass::method() called at [/www/education/error/backtrace.php:14]

Проверить код на наличие синтаксических ошибок можно с помощью функции php_check_syntax() или же команды php -l [путь к файлу], но я не встречал использования оных.

Assert

Отдельно хочу рассказать о таком экзотическом звере как assert() в PHP, собственно это кусочек контрактной методологии программирования, и дальше я расскажу вам как я никогда его не использовал 🙂

Первый случай – это когда вам надо написать TODO прямо в коде, да так, чтобы точно не забыть реализовать заданный функционал:

// включаем вывод ошибок
error_reporting(E_ALL);
ini_set('display_errors', 1);

// включаем asserts
ini_set('zend.assertions', 1);
ini_set('assert.active', 1);

assert(false, "Remove it!");

В результате выполнения данного кода получим E_WARNING:

Warning: assert(): Remove it! failed

PHP7 можно переключить в режим exception, и вместо ошибки будет всегда появляться исключение AssertionError:

// включаем asserts
ini_set('zend.assertions', 1);
ini_set('assert.active', 1);
// переключаем на исключения
ini_set('assert.exception', 1);

assert(false, "Remove it!");

В результате ожидаемо получаем не пойманный AssertionError. При необходимости, можно выбрасывать произвольное исключение:

assert(false, new Exception("Remove it!"));

Но я бы рекомендовал использовать метки @TODO, современные IDE отлично с ними работают, и вам не нужно будет прикладывать дополнительные усилия и ресурсы для работы с ними

Второй вариант использования – это создание некоего подобия TDD, но помните – это лишь подобие. Хотя, если сильно постараться, то можно получить забавный результат, который поможет в тестировании вашего кода:

// callback-функция для вывода информации в браузер
function backlog($script, $line, $code, $message) {
    echo "<h3>$message</h3>";
    highlight_string ($code);
}

// устанавливаем callback-функцию
assert_options(ASSERT_CALLBACK, 'backlog');
// отключаем вывод предупреждений
assert_options(ASSERT_WARNING,  false);

// пишем проверку и её описание
assert("sqr(4) == 16", "When I send integer, function should return square of it");

// функция, которую проверяем
function sqr($a) {
    return; // она не работает
}

Третий теоретический вариант – это непосредственно контрактное программирование – когда вы описали правила использования своей библиотеки, но хотите точно убедится, что вас поняли правильно, и в случае чего сразу указать разработчику на ошибку (я вот даже не уверен, что правильно его понимаю, но пример кода вполне рабочий):

/**
 * Настройки соединения должны передаваться в следующем виде
 *
 *     [
 *         'host' => 'localhost',
 *         'port' => 3306,
 *         'name' => 'dbname',
 *         'user' => 'root',
 *         'pass' => ''
 *     ]
 *
 * @param $settings
 */
function setupDb ($settings) {
    // проверяем настройки
    assert(isset($settings['host']), 'Db `host` is required');
    assert(isset($settings['port']) && is_int($settings['port']), 'Db `port` is required, should be integer');
    assert(isset($settings['name']), 'Db `name` is required, should be integer');

    // соединяем с БД
    // ...
}

setupDb(['host' => 'localhost']);

Никогда не используйте assert() для проверки входных параметров, ведь фактически assert() интерпретирует строковую переменную (ведёт себя как eval()), а это чревато PHP-инъекцией. И да, это правильное поведение, т.к. просто отключив assert’ы всё что передаётся внутрь будет проигнорировано, а если делать как в примере выше, то код будет выполняться, а внутрь отключенного assert’a будет передан булевый результат выполнения

Если у вас есть живой опыт использования assert() – поделитесь со мной, буду благодарен. И да, вот вам ещё занимательно чтива по этой теме – PHP Assertions, с таким же вопросом в конце 🙂

В заключение

Я за вас напишу выводы из данной статьи:

  • Ошибкам бой – их не должно быть в вашем коде
  • Используйте исключения – работу с ними нужно правильно организовать и будет счастье
  • Assert – узнали о них, и хорошо

P.S. Спасибо Максиму Слесаренко за помощь в написании статьи

0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии

А вот еще интересные материалы:

  • Яшка сломя голову остановился исправьте ошибки
  • Ясность цели позволяет целеустремленно добиваться намеченного исправьте ошибки
  • Ясность цели позволяет целеустремленно добиваться намеченного где ошибка
  • Php не выводятся ошибки
  • Php не выводить ошибки на экран