Настройка вывода сообщений об ошибках: display_errors и error_reporting

Раздел: Администрирование PHP -> Настройка PHP

Основные методы настройки отображения ошибок в PHP

Настройка через php.ini (основной и постоянный способ)

Файл php.ini предоставляет централизованное управление директивами display_errors и error_reporting. Изменения действуют для всех скриптов на сервере (или в директории, если используется пользовательский php.ini).

Пример конфигурации для окружения разработки (все ошибки выводятся):


; php.ini
display_errors = On
error_reporting = E_ALL
  

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


; php.ini
display_errors = Off
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
  

Типичная проблема: После изменения php.ini требуется перезапуск веб-сервера или PHP-FPM, иначе новые настройки не вступят в силу. Проверить действующие значения можно через phpinfo().

Цель: Единая конфигурация для всего сервера или виртуального хоста. Используется администраторами при развёртывании проектов.

Как настроить отображение ошибок через .htaccess (для Apache)?

Если нет доступа к основному php.ini, можно переопределить директивы в файле .htaccess (при включённом AllowOverride Options).


# .htaccess
php_value display_errors On
php_value error_reporting -1
  

Значение -1 соответствует E_ALL (все уровни, включая будущие).

Возможная ошибка: Директива php_value не работает в .htaccess, если PHP работает как модуль Apache и AllowOverride не включает Options. Вместо этого может потребоваться SetEnv или конфигурация через vhost.

Цель: Локальная настройка для конкретного сайта или подпапки, когда нет прав на изменение php.ini.

Как временно включить вывод ошибок в PHP-скрипте с помощью ini_set?

Функция ini_set() позволяет изменить директивы во время выполнения скрипта. Подходит для отладки конкретного участка кода.


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

Важно: ini_set('display_errors', '1') должен быть вызван до любого вывода HTML или отправки заголовков, иначе возникнет ошибка 'headers already sent'.

Проблема: Если скрипт уже отправил данные, ini_set('display_errors', '1') не даст эффекта; ошибки по-прежнему не будут отображаться, так как буфер вывода уже отправлен.

Цель: Быстрая отладка в одном файле без изменения глобальных настроек.

Как настроить уровень отчёта об ошибках через функцию error_reporting?

Функция error_reporting() устанавливает уровень ошибок для текущего скрипта, при этом display_errors остаётся прежним.


<?php
error_reporting(E_ALL & ~E_NOTICE & ~E_WARNING);
  

Она не влияет на отображение ошибок, только на то, какие типы будут перехватываться.

Распространённая ошибка: Разработчики путают error_reporting() и ini_set('display_errors'). Первое управляет фильтрацией, второе - выводом. Для полного контроля нужны обе настройки.

Цель: Игнорировать незначительные предупреждения (например, E_NOTICE) при разработке или на продакшене.

Как использовать константу -1 для включения всех ошибок?

Значение -1 в error_reporting или E_ALL включает все известные и будущие уровни ошибок. Это удобно для окружения разработки.


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

Недостаток: На боевом сервере -1 может выводить слишком много информации, включая deprecation notices, что нежелательно.

Цель: Максимально детальная отладка на локальной машине.

Как отключить display_errors только для продакшена, оставив логирование?

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


php_value display_errors Off
php_value log_errors On
php_value error_log /path/to/error.log
  

Проблема: Если путь к логу неверен или нет прав на запись, ошибки могут не регистрироваться. Необходимо проверить, что файл создаётся и доступен для записи веб-сервером.

Цель: Соблюдение безопасности и возможность анализа ошибок в логах без раскрытия информации пользователю.

Как настроить отображение ошибок для командной строки (CLI)?

При запуске PHP из командной строки можно передать директивы через флаг -d:


php -d display_errors=1 -d error_reporting=-1 script.php
  

Также можно использовать отдельный php.ini для CLI, расположенный в /etc/php/X.Y/cli/php.ini.

Нюанс: Для CLI значения по умолчанию могут отличаться от веб-версии. Например, display_errors в CLI часто включён, но для веба выключен.

Цель: Отладка скриптов, запускаемых через cron или консоль.

Что делать, если ошибка появляется, но не выводится (скрытый белый экран)?

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

  • display_errors – должен быть включён;
  • error_reporting – должен включать уровень ошибки;
  • display_startup_errors – для ошибок, возникающих при запуске PHP (например, при загрузке расширений).

; php.ini
display_startup_errors = On
display_errors = On
error_reporting = E_ALL
  

Типичная ошибка: Разработчик включает display_errors и error_reporting, но забывает про display_startup_errors. В результате фатальные ошибки на старте (например, синтаксическая ошибка в подключаемом файле) не выводятся, хотя в log попадают.

Цель: Выявление ошибок, возникающих до загрузки основного кода (например, в autoloader или при загрузке расширений).

Расширенные примеры настройки и отладки ошибок

Пример 1. Использование битовых масок для тонкой настройки error_reporting

Можно комбинировать уровни ошибок с помощью побитовых операторов. Например, показать только предупреждения и уведомления, но не Deprecated.

Пример

<?php
// Показать только E_WARNING и E_NOTICE, игнорируя всё остальное
error_reporting(E_WARNING | E_NOTICE);

// Вызов предупреждения
trigger_error('Это предупреждение', E_WARNING);

// Вызов уведомления
echo $undefined_variable;
?>
  

Результат выполнения скрипта (при включённом display_errors):

Warning: Это предупреждение in /path/script.php on line 6

Notice: Undefined variable: undefined_variable in /path/script.php on line 9
  

Пояснение: Побитовое ИЛИ (|) объединяет константы. Такой подход удобен, когда нужно отфильтровать только определённые типы ошибок, исключив всё лишнее.

Пример 2. Использование ini_set для временного включения отображения ошибок в середине скрипта (с проверкой буфера вывода)

Чтобы избежать ошибки 'headers already sent', можно проверить, не был ли уже отправлен вывод, и использовать буферизацию.

Пример

<?php
// Включение буферизации вывода
ob_start();

// Какой-то код, который может генерировать ошибки
echo 'Начало вывода';

// Проверка, можно ли ещё менять заголовки
if (!headers_sent()) {
    ini_set('display_errors', '1');
    ini_set('error_reporting', E_ALL);
}

// Ошибка
trigger_error('Тестовая ошибка', E_USER_WARNING);

// Отправка буфера
ob_end_flush();
?>
  

Результат:

WARNING: ...
Начало вывода
  

Пояснение: Буферизация позволяет накапливать вывод, изменять настройки до отправки заголовков, а затем вывести содержимое. Без буферизации после первого echo изменение display_errors уже не сработает.

Пример 3. Раздельная настройка для разных уровней ошибок (E_USER_* и системных)

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

Пример

<?php
set_error_handler(function($severity, $message, $file, $line) {
    // Пропустить все, кроме E_USER_WARNING и E_USER_NOTICE
    if (!($severity & (E_USER_WARNING | E_USER_NOTICE))) {
        return false; // стандартная обработка PHP
    }
    echo "Пользовательская ошибка: [$severity] $message в $file:$line\n";
}, E_ALL);

trigger_error('Это пользовательское предупреждение', E_USER_WARNING);

echo $undefined; // это E_NOTICE не будет выведено нашим обработчиком, а пойдёт в стандартный
?>
  

Результат (при display_errors = On и error_reporting = E_ALL):

Пользовательская ошибка: [512] Это пользовательское предупреждение в /path/script.php:15
Notice: Undefined variable: undefined in /path/script.php on line 17
  

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

Пример 4. Настройка display_errors через файл .user.ini (для PHP-FPM и CGI)

Когда используется PHP-FPM или CGI, можно разместить файл .user.ini в корневой директории проекта. Он читается как php.ini для данной папки (аналогично .htaccess, но не требует Apache).

Пример

; .user.ini
display_errors = On
error_reporting = E_ALL
  

Не нужно перезапускать FPM, так как файл проверяется при каждом запросе.

Пояснение: Это удобно для хостингов, где нет доступа к глобальному php.ini. Файл помещается в корень сайта и действует рекурсивно.

Пример 5. Использование ini_get для диагностики текущих настроек

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

Пример

<?php
echo 'display_errors: ' . ini_get('display_errors') . "\n";
echo 'error_reporting: ' . ini_get('error_reporting') . "\n";
echo 'log_errors: ' . ini_get('log_errors') . "\n";
?>
  

Результат (пример):

display_errors: 1
error_reporting: 32767
log_errors: 0
  

Пояснение: Значение 32767 соответствует E_ALL в 32-битной системе. Вывод помогает убедиться, что настройки действительно были изменены.

Пример 6. Комбинация error_reporting и display_errors для отладки конкретного модуля

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

Пример

<?php
// index.php
ini_set('display_errors', '0');
error_reporting(E_ALL & ~E_NOTICE);

// ... код ...

// Подключаем отладочный модуль
$old = ini_get('display_errors');
ini_set('display_errors', '1');
error_reporting(E_ALL);

include 'debug_module.php';

// Восстанавливаем настройки
ini_set('display_errors', $old);
error_reporting(E_ALL & ~E_NOTICE);

// ... остальной код ...
?>
  

Пояснение: Сохранение и восстановление предыдущих настроек через ini_get позволяет изолировать отладку без побочных эффектов для остальной части приложения.

Пример 7. Настройка display_errors через php.ini для PHP-FPM pool

В конфигурации пула FPM (обычно /etc/php/*/fpm/pool.d/*.conf) можно задать директивы через php_admin_value или php_value. Этот способ не допускает переопределения через ini_set в коде.

Пример

; pool.conf
php_admin_value[display_errors] = On
php_admin_value[error_reporting] = E_ALL
  

После изменения нужно перезагрузить FPM: systemctl reload php*-fpm.

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

Пример 8. Ошибка при использовании display_errors с кэшированием через OPCache

Если используется OPCache, изменение настроек через ini_set работает, но может не отразиться на кэшированных скриптах, если они уже скомпилированы с отключённым отображением. Решение – на время отладки отключить OPCache или очистить его.

Пример

// Временно отключить кэширование OPCache
ini_set('opcache.enable', '0');
// или очистить кэш
opcache_reset();
  

Пояснение: OPCache хранит скомпилированный код, и настройки display_errors применяются на этапе выполнения, поэтому очистка кэша не всегда обязательна, но если ошибка скрыта из-за того, что код не перекомпилирован, помогает.

Настройка отображения ошибок в PHP (display_errors, error_reporting) - comments

En
Php ini set error (php)