set_error_handler()
Функция set_error_handler() в PHP позволяет регистрировать пользовательский обработчик ошибок вместо стандартного поведения.
По умолчанию PHP при нефатальной ошибке выводит сообщение (или записывает его в лог) и продолжает выполнение. В продакшне это редко бывает нужным: сырое сообщение может раскрыть посетителям пути к файлам, а у вас не будет единого места для логирования, форматирования или преобразования ошибок. Функция set_error_handler() решает эту проблему, направляя встроенные ошибки PHP через функцию, которую вы контролируете.
В этой главе объясняется, что делает set_error_handler(), какую сигнатуру обратного вызова ожидает PHP, какие ошибки можно и нельзя перехватить, а также как использовать функцию для чистого логирования.
Что делает set_error_handler()
set_error_handler() регистрирует обратный вызов, который PHP вызывает вместо встроенного обработчика ошибок при возникновении соответствующей (нефатальной) ошибки. Ваш обратный вызов решает, что происходит дальше — записать в лог, отобразить дружелюбное сообщение, выбросить исключение или просто проигнорировать.
Функция не останавливает возникновение ошибок — она лишь меняет способ их обработки. PHP по-прежнему учитывает error_reporting при решении о том, вызывать ли ваш обработчик вообще.
Синтаксис
set_error_handler(
callable|null $callback,
int $error_levels = E_ALL
): callable|false| Параметр | Описание |
|---|---|
$callback | Функция, которую PHP вызывает при возникновении ошибки. Передайте null, чтобы восстановить встроенный обработчик PHP. |
$error_levels | Битовая маска уровней ошибок, которые должен получать ваш обработчик (например, E_WARNING | E_NOTICE). По умолчанию E_ALL. |
Возвращаемое значение: ранее зарегистрированный обработчик (callable) или null, если такого не было. Возвращает false только в случае недопустимого обратного вызова.
Сигнатура обратного вызова
PHP вызывает ваш обработчик с пятью аргументами. Чаще всего используются первые четыре:
function handler(
int $errno, // the error level constant, e.g. E_WARNING
string $errstr, // the error message
string $errfile = "", // file where the error occurred
int $errline = 0 // line number
): bool {
// ...
}Если ваш обработчик возвращает false, PHP продолжает стандартную внутреннюю обработку ошибки. Возврат true (или отсутствие возврата) сигнализирует PHP, что ошибка полностью обработана, и подавляет поведение по умолчанию.
Какие ошибки можно перехватить
set_error_handler() перехватывает пользовательски перехватываемые уровни ошибок — предупреждения, уведомления, устаревший код и семейство E_USER_*, которые поднимаются с помощью trigger_error():
| Перехватываемые | Не перехватываемые (фатальные) |
|---|---|
E_WARNING, E_NOTICE, E_DEPRECATED | E_ERROR |
E_USER_ERROR, E_USER_WARNING, E_USER_NOTICE | E_PARSE |
E_RECOVERABLE_ERROR, E_STRICT | E_CORE_ERROR, E_COMPILE_ERROR |
Примечание: Фатальные ошибки, такие как
E_ERRORиE_PARSE, обходят ваш обработчик и завершают скрипт. Чтобы перехватывать и их, используйте обработчик в сочетании сset_exception_handler()и функцией завершения. Неперехваченные исключения также не направляются сюда — для них есть отдельный обработчик.
Простой обработчик
Определите функцию с ожидаемой сигнатурой и зарегистрируйте её. Здесь вызов trigger_error() имитирует предупреждение, чтобы вы могли увидеть работу обработчика:
<?php
function customErrorHandler($errno, $errstr, $errfile, $errline)
{
echo "Handled error [$errno]: $errstr in $errfile on line $errline\n";
return true; // we consider the error fully handled
}
set_error_handler("customErrorHandler");
trigger_error("This is a test warning", E_USER_WARNING);
// Restore PHP's default error handling
restore_error_handler();Вывод:
Handled error [512]: This is a test warning in ... on line 11512 — числовое значение E_USER_WARNING. После вызова restore_error_handler() ошибки возвращаются к поведению PHP по умолчанию.
Преобразование ошибок в исключения
Распространённый паттерн в продакшне — преобразование предупреждений и уведомлений в исключения, чтобы они проходили через обычную логику try/catch. Это позволяет обрабатывать ошибки file_get_contents() (которая выдаёт только предупреждение) с помощью try/catch:
<?php
set_error_handler(function ($errno, $errstr, $errfile, $errline) {
// Respect the @ operator and error_reporting settings.
if (!(error_reporting() & $errno)) {
return false;
}
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
});
try {
$data = file_get_contents("/no/such/file");
} catch (ErrorException $e) {
echo "Caught: " . $e->getMessage() . "\n";
}Вывод:
Caught: file_get_contents(/no/such/file): Failed to open stream: No such file or directoryЛогирование вместо отображения
Сопоставление константы уровня с читаемой меткой делает логи удобнее для просмотра. Используйте error_log() для записи в настроенный назначенный журнал:
<?php
set_error_handler(function ($errno, $errstr, $errfile, $errline) {
$levels = [
E_WARNING => "WARNING",
E_NOTICE => "NOTICE",
E_DEPRECATED => "DEPRECATED",
E_USER_WARNING => "USER_WARNING",
];
$label = $levels[$errno] ?? "UNKNOWN($errno)";
$line = "[$label] $errstr in $errfile:$errline";
error_log($line); // goes to your log, not the page
echo $line . "\n"; // shown here only to demonstrate the output
return true;
});
trigger_error("Disk space low", E_USER_WARNING);Вывод:
[USER_WARNING] Disk space low in ... :15Подводные камни
- Оператор
@. Когда ошибка подавляется с помощью@, функцияerror_reporting()возвращает0внутри вашего обработчика. Проверяйтеerror_reporting() & $errno, если хотите учитывать@, как показано выше. - Фатальные ошибки по-прежнему ускользают. Независимо от второго аргумента,
E_ERRORи ошибки синтаксиса никогда не передаются вашему обработчику. - Обработчик глобален. Зарегистрированный обработчик влияет на весь запрос. Библиотеки, устанавливающие собственный обработчик, могут перезаписать ваш, поэтому восстанавливайте обработчики после завершения работы.
- Не используйте
echoв продакшне. Отображение сырых сообщений раскрывает пути и помогает злоумышленникам — записывайте их в лог и показывайте пользователю обобщённую страницу.
Связанные функции
restore_error_handler()— восстановить предыдущий обработчик.trigger_error()— вызвать собственные ошибкиE_USER_*.error_reporting()— управлять активными уровнями ошибок.set_exception_handler()— перехватывать неперехваченные исключения.
Заключение
set_error_handler() даёт вам единое место для перехвата нефатальных ошибок PHP и применения собственной логики — записывать в лог, преобразовывать в исключения или скрывать от пользователей. Сочетайте её с обработчиком исключений и правильным логированием для обработки ошибок уровня продакшна. Помните об одном жёстком ограничении: фатальные ошибки и ошибки синтаксиса полностью обходят этот обработчик.