PHP 8.5: Поддержка трассировки стека для фатальных ошибок PHP
Одним из наиболее значительных изменений в PHP 7.0 стала замена нескольких условий ошибок PHP на исключения Error вместо вызова фатальной ошибки. Ошибки типов, синтаксические ошибки и несколько других видов ошибок стали исключениями в современных версиях PHP.
Также PHP поддерживает настройку пользовательского обработчика ошибок, поэтому некоторые ошибки, такие как уведомления об устаревании, предупреждения и другие уведомления, также могут быть занесены в лог.
Однако в PHP всё ещё существуют определённые неисправимые ошибки, при возникновении которых просто выводится сообщение об ошибке и происходит немедленный выход из программы (после вызова функции завершения работы, если она задана с помощью register_shutdown_function и её можно вызвать на данном этапе).
ini_set('memory_limit', '2M');
function my_heavy_function(): void {
$str = str_repeat('A', 1024 * 1024 * 5);
}
my_heavy_function();Вышеприведённый фрагмент PHP кода вызывает фатальную ошибку, поскольку в нём устанавливается значение memory_limit равным 2 МБ, а функция my_heavy_function() потребляет больше памяти, чем это ограничение.
До PHP 8.5, PHP завершается с таким сообщением:
Fatal error: Allowed memory size of 2097152 bytes exhausted (tried to allocate 5242912 bytes) in ... on line ...Хотя в сообщении об ошибке указаны имя файла и номер строки, в которой произошла ошибка, в нём отсутствует трассировка стека. Без трассировки стека сложно отследить стек вызывающих функций, приведших к этой строке в скрипте.
В PHP 8.5 добавлена новая возможность, благодаря которой сообщения о фатальных ошибках содержат полную трассировку стека:
Fatal error: Allowed memory size of 2097152 bytes exhausted (tried to allocate 5242912 bytes) in /mnt/w/localhost/test/php85/error_handlers.php on line 6
Stack trace:
#0 file.php(...): str_repeat('A', 5242880)
#1 file.php(...): my_heavy_function()
#2 {main}Новая INI-директива fatal_error_backtraces
Новая трассировка стека фатальных ошибок включена по умолчанию и может быть отключена с помощью новой INI-директивы fatal_error_backtraces.
Например, для отключения трассировки фатальных ошибок установите INI директиву, как показано ниже:
fatal_error_backtraces = OffСовместимость с другими инструментами обработки ошибок
Новая возможность трассировки фатальных ошибок работает также с другими INI директивами.
- С INI директивой
display_errors=Offсообщения об ошибках теперь отображаются на экране; обратная трассировка также не отображается. - Параметры, помеченные
#[\SensitiveParameter], не раскрывают содержимое аргументов, переданных этому параметру. - С INI директивой
zend.exception_ignore_argsобратная трассировка не содержит переданных аргументов.
Почему обратные трассировки включаются только для фатальных ошибок
Трассировки, включающие аргументы, приводят к увеличению счётчика ссылок для этих аргументов. В результате аргументы сохраняют активность вплоть до момента уничтожения трассировки.
Поскольку функция error_get_last возвращает трассировку последней возникшей ошибки, разработчики могут столкнуться с неожиданным поведением: объекты остаются активными дольше предполагаемого срока. Это продолжается либо до вызова функции error_clear_last, либо до возникновения новой ошибки.
Ограничение данной функциональности исключительно фатальными ошибками (E_FATAL_ERRORS) позволяет свести к минимуму указанный побочный эффект, ограничивая его лишь нестандартными ситуациями.
В случае фатальной ошибки PHP запускает обработчики завершения работы. При разработке кода для таких обработчиков необходимо учитывать, что приложение может находиться в нестабильном или аномальном состоянии.
Кроме того, в современных PHP‑приложениях распространена практика преобразования предупреждений и уведомлений PHP в исключения посредством функции set_error_handler. В результате формируется обратная трассировка через объект Error.
Однако для фатальных ошибок (E_FATAL_ERRORS) создание трассировок невозможно — такие ошибки не поддаются обработке в коде приложения.
Влияние на обратную совместимость
Эта функция не вызывает никаких проблем с обратной совместимостью.
Установка INI директивы fatal_error_backtraces = Off отключает эту функциональную возможность. Однако обратите внимание, что отключение отображения ошибок с помощью директивы display_errors=Off является рекомендуемым способом защиты рабочих систем от утечки внутренней информации.