Menu

Вывод ошибок PHP: display_errors и E_ALL

Чтобы показать все ошибки PHP, поставьте ini_set('display_errors', '1'); и error_reporting(E_ALL); в начало скрипта или задайте display_errors = On и error_reporting = E_ALL в php.ini. В продакшене ошибки пишут в лог, а не показывают.

На этой странице есть исполняемые редакторы: меняйте, запускайте и сразу видите результат.

Чтобы показать ошибки PHP, поставьте в начало скрипта строки ini_set('display_errors', '1'); и error_reporting(E_ALL);. Первая заставляет PHP печатать сообщения об ошибках, вторая включает сообщения обо всех видах ошибок, включая предупреждения и устаревший код.

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

После этого ошибка вроде чтения переменной, которой никогда не присваивали значение, выводит сообщение с файлом и номером строки, а не проходит молча:

Warning: Undefined variable $total in /home/index.php on line 7

error_reporting() без аргумента возвращает текущую настройку в виде числа. Нажмите Run, чтобы задать уровень и расшифровать его обратно в имена:

Каждый тип ошибки занимает один бит, поэтому E_ALL & ~E_DEPRECATED означает "всё, кроме устаревшего кода". Замените первую строку на error_reporting(E_ERROR | E_WARNING); и запустите снова.

Вывод ошибок в php.ini

Настройка в скрипте начинает действовать только после того, как скрипт запустился. Чтобы показывать ошибки во всех скриптах, включая ошибки разбора, измените php.ini (найти его можно командой php --ini):

; Development
display_errors = On
display_startup_errors = On
error_reporting = E_ALL

После правки перезапустите Apache или PHP-FPM. Встроенный сервер php -S и командная строка читают файл при каждом запуске. На виртуальном хостинге без доступа к php.ini Apache с mod_php принимает и строки в .htaccess:

php_flag display_errors on
php_value error_reporting -1

-1 устанавливает все биты, это то же самое, что E_ALL.

Уровни ошибок

КонстантаЧто её вызываетОстанавливает скрипт
E_ERRORФатальная ошибка выполнения, например нехватка памятида
E_PARSEСинтаксическая ошибка в файледа
E_WARNINGНеопределённая переменная или ключ массива, отсутствующий файл в includeнет
E_NOTICEМелкие проблемы (в PHP 8 их почти не осталось)нет
E_DEPRECATEDКод, который будущая версия PHP отвергнетнет
E_USER_*Ошибки, которые вы вызываете через trigger_error()только E_USER_ERROR
E_ALLВсе уровни, включая ошибки ядра и компиляции, не перечисленные здесь

PHP 8.0 превратил многие старые предупреждения в исключения: деление на ноль через / и передача неверного типа во встроенную функцию теперь выбрасывают подкласс Error, как и вызов неопределённой функции начиная с PHP 7. Все три можно перехватить:

Исключения описаны в try и catch. Предупреждения, notice и сообщения об устаревшем коде по-прежнему проходят через систему вывода ошибок, описанную здесь.

Запись ошибок в лог вместо вывода

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

; Production
display_errors = Off
log_errors = On
error_log = /var/log/php/app-errors.log
error_reporting = E_ALL

Оставляйте error_reporting = E_ALL в продакшене. Если понизить уровень, ошибки никуда не денутся, вы просто перестанете о них узнавать. Свои сообщения можно писать в тот же лог через error_log():

<?php
error_log("Payment failed for order 1042");

Затем следите за файлом во время тестирования: tail -f /var/log/php/app-errors.log.

Предупреждения как исключения через set_error_handler

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

Обработчик получает уровень ошибки первым аргументом, поэтому может обрабатывать уровни по-разному. Этот только записывает в лог устаревший код, а всё остальное превращает в исключение:

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

Последняя ошибка через error_get_last

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

Оператор @ перед вызовом подавляет сообщение для этого одного выражения. Пользуйтесь им редко и только тогда, когда сразу проверяете результат, как здесь; @ сам по себе только прячет ошибки.

Частая ошибка: вывод ошибок включён, а страница всё равно пустая

Если вы добавили ini_set('display_errors', '1') и всё равно видите белую страницу, скорее всего, это ошибка разбора. PHP разбирает весь файл до выполнения первой строки, поэтому пропущенная ; или } останавливает всё ещё до того, как сработает ini_set. Проверьте файл из терминала, он всегда печатает сообщение:

php -l index.php
Errors parsing index.php
PHP Parse error:  syntax error, unexpected token "," in index.php on line 2

Номер строки указывает, где PHP сдался, а это часто строка после настоящей ошибки. Исправьте её, запускайте php -l снова, пока не увидите No syntax errors detected, и перезагрузите страницу.

Часто задаваемые вопросы

Как включить вывод всех ошибок в PHP?

Добавьте ini_set('display_errors', '1'); ini_set('display_startup_errors', '1'); error_reporting(E_ALL); в самое начало скрипта или задайте display_errors = On и error_reporting = E_ALL в php.ini и перезапустите веб-сервер или PHP-FPM.

Почему PHP-страница показывает пустой белый экран?

Фатальная ошибка остановила скрипт, а display_errors выключен, поэтому ничего не напечаталось. Включите вывод ошибок (или прочитайте лог ошибок, например через tail -f по файлу, на который указывает error_log), чтобы увидеть сообщение и номер строки.

Почему ini_set('display_errors', 1) не показывает ошибку разбора?

Ошибка разбора останавливает PHP до выполнения первой строки файла, поэтому вызов ini_set так и не происходит. Задайте display_errors в php.ini или поместите ini_set в небольшой файл, который потом делает include сломанного.

Нужно ли включать display_errors в продакшене?

Нет. Сообщения об ошибках раскрывают посетителям пути к файлам и детали кода. В продакшене используйте display_errors = Off, log_errors = On и путь в error_log, а error_reporting = E_ALL оставьте, чтобы проблемы всё равно записывались.

Что делает error_reporting(0)?

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

Иллюстрация языков программирования Coddy

Учитесь программировать с Coddy

НАЧАТЬ