Вывод ошибок PHP: конфигурация и обработка

Раздел: PHP -> Настройка вывода ошибок PHP

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

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

Наиболее эффективный способ для локальной разработки - установка директив display_errors и error_reporting в начале скрипта. Это гарантирует, что все ошибки, включая синтаксические, будут отображены.

ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

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

Если ошибка происходит до выполнения ini_set (например, в синтаксисе самого скрипта), она не будет показана. Для решения необходимо настроить php.ini или .htaccess. Также не следует оставлять эти директивы включёнными на боевом сервере - это может раскрыть конфиденциальные данные.

Как настроить вывод ошибок через php.ini?

Глобальная настройка в файле php.ini применяется ко всем скриптам на сервере. Для локальной среды можно установить:

display_errors = On
display_startup_errors = On
error_reporting = E_ALL

Для боевого сервера:

display_errors = Off
display_startup_errors = Off
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
log_errors = On

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

Необходимо перезагрузить веб-сервер после изменения php.ini. Если файл недоступен (например, на shared хостинге), используйте .htaccess или ini_set.

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

Если нет доступа к php.ini, можно задать директивы через .htaccess в корне сайта:

php_value display_errors 1
php_value display_startup_errors 1
php_value error_reporting -1

-1 соответствует E_ALL. Для отключения замените 1 на 0 и установите нужный уровень.

Директивы работают только на серверах Apache с модулем mod_php. На Nginx или при использовании CGI/FPM этот способ не сработает.

Как задать определённый уровень отчёта об ошибках?

Функция error_reporting() принимает битовую маску. Примеры:

error_reporting(E_ALL & ~E_NOTICE);          // все, кроме уведомлений
error_reporting(E_ERROR | E_WARNING);       // только фатальные ошибки и предупреждения
error_reporting(0);                         // отключить отчёт полностью

Уровни можно комбинировать. На этапе разработки рекомендуется E_ALL, на продакшене - E_ALL & ~E_DEPRECATED & ~E_STRICT с логированием.

Некоторые устаревшие конструкции могут генерировать E_DEPRECATED, что засоряет лог. Поэтому их часто исключают.

Как выводить исключения с помощью try-catch?

Исключения (Throwable) не обрабатываются стандартным выводом ошибок, их нужно ловить вручную. Пример:

try {
    throw new Exception('Произошла ошибка');
} catch (Exception $e) {
    echo 'Поймано исключение: ' . $e->getMessage();
}

Также можно ловить все типы ошибок, используя базовый тип \Throwable.

Если исключение не перехвачено, PHP выдаёт фатальную ошибку, которую стандартные настройки не показывают, если display_errors выключен. Для этого используйте set_exception_handler.

Как создать собственный обработчик ошибок?

Функция set_error_handler() перехватывает нефатальные ошибки. Пример вывода в красивом формате:

function customError($severity, $message, $file, $line) {
    echo "<b>Ошибка:</b> [$severity] $message в файле $file на строке $line";
}
set_error_handler("customError");
echo $undefinedVar; // вызовет обработчик

Обработчик не ловит фатальные ошибки (E_ERROR, E_PARSE). Для них нужен register_shutdown_function.

Если в пользовательском обработчике допущена ошибка, она может быть не видна. Лучше возвращать true для продолжения работы.

Как записывать ошибки в файл лога?

Включение log_errors и указание error_log:

ini_set('log_errors', 1);
ini_set('error_log', '/var/log/php_errors.log');
error_reporting(E_ALL);

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

Если файл лога не создаётся, проверьте права на папку. Можно использовать системный лог (syslog).

Как отловить фатальные ошибки (E_ERROR, E_PARSE)?

Фатальные ошибки не перехватываются set_error_handler. Используйте register_shutdown_function вместе с error_get_last:

register_shutdown_function(function() {
    $error = error_get_last();
    if ($error && ($error['type'] === E_ERROR || $error['type'] === E_PARSE)) {
        echo "Фатальная ошибка: {$error['message']} в {$error['file']}:{$error['line']}";
    }
});
// Вызов несуществующей функции
testFunc();

Эта конструкция показывает фатальные ошибки даже при выключенном display_errors.

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

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

Ниже приведены практические сценарии с кодом и результатами их выполнения.

Пример 1. Комбинированная настройка для разработки

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

Пример
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

// Пользовательский обработчик нефатальных ошибок
set_error_handler(function($severity, $message, $file, $line) {
    $output = "<b>Ошибка уровня $severity:</b> $message в $file:$line";
    echo "<div style='color:red;'>$output</div>";
});

// Обработка фатальных ошибок
register_shutdown_function(function() {
    $error = error_get_last();
    if ($error && ($error['type'] === E_ERROR || $error['type'] === E_PARSE)) {
        echo "<div style='color:darkred; font-weight:bold;'>Фатальная ошибка: {$error['message']} в {$error['file']}:{$error['line']}</div>";
    }
});

// Демонстрация
echo $undefinedVar; // Notice
trigger_error('Пользовательское предупреждение', E_USER_WARNING);

Результат выполнения (вывод в браузере):

Ошибка уровня 8: Undefined variable: undefinedVar в /var/www/example.php:17
Ошибка уровня 512: Пользовательское предупреждение в /var/www/example.php:18

При вызове несуществующей функции (например, badFunc()) на экране появится сообщение о фатальной ошибке.

Пример 2. Логирование с разными стилями вывода

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

Пример
ini_set('display_errors', 0);
ini_set('log_errors', 1);
ini_set('error_log', __DIR__.'/errors.log');
error_reporting(E_ALL);

set_error_handler(function($severity, $message, $file, $line) {
    $logEntry = date('Y-m-d H:i:s')." [$severity] $message in $file:$line".PHP_EOL;
    file_put_contents(ini_get('error_log'), $logEntry, FILE_APPEND);
    echo "<p>Извините, произошла ошибка. Администратор уведомлен.</p>";
});

file_get_contents('/несуществующий_файл');

Содержимое errors.log после запуска:

2025-03-25 14:30:12 [2] file_get_contents(/несуществующий_файл): Failed to open stream: No such file or directory in /var/www/example.php:13

Пользователь видит только вежливое сообщение, а техническая информация сохраняется в логе.

Пример 3. Отлов исключений через set_exception_handler

Глобальный обработчик неперехваченных исключений.

Пример
set_exception_handler(function(\Throwable $exception) {
    echo "<b>Необработанное исключение:</b> " . $exception->getMessage();
    echo "<br>Файл: {$exception->getFile()}, строка {$exception->getLine()}";
});

throw new \InvalidArgumentException('Неверный аргумент');

Результат:

Необработанное исключение: Неверный аргумент
Файл: /var/www/example.php, строка 6

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

Пример 4. Использование error_reporting с битовыми масками

Демонстрация разных уровней.

Пример
error_reporting(E_ALL & ~E_NOTICE);
echo $notSet; // Notice подавлен, ничего не выведется

trigger_error('Это предупреждение', E_USER_WARNING); // будет выведено

// Включить обратно уведомления
error_reporting(E_ALL);
echo $notSet; // Notice теперь отображается

Вывод:

Notice: Undefined variable: notSet in /var/www/example.php на строке 9

Первое обращение к $notSet не вызвало сообщения, второе - вызвало, так как маска была изменена.

Пример 5. Проверка error_get_last после выполнения скрипта

Получение последней ошибки для кастомной обработки.

Пример
$result = @file_get_contents('http://example.com/notfound');
if ($result === false) {
    $lastError = error_get_last();
    if ($lastError) {
        echo "Не удалось загрузить: {$lastError['message']}";
    }
}

Результат:

Не удалось загрузить: file_get_contents(http://example.com/notfound): Failed to open stream: HTTP request failed! HTTP/1.1 404 Not Found

Здесь оператор @ подавляет вывод ошибки, но error_get_last позволяет её извлечь.

Вывод ошибок PHP - comments

En
вывод ошибок php (php)