debug_backtrace() из зарегистрированной функции выключения в PHP
Разрабатывая ответ на этот вопрос, я обнаружил, что debug_backtrace()
не выходит за пределы функции, зарегистрированной для register_shutdown_function()
когда вызывается изнутри.
Это было упомянуто в этом комментарии для register_shutdown_function()
в документации PHP, заявив:
Вы можете получить идею вызвать debug_backtrace или debug_print_backtrace из функции завершения работы, чтобы отследить, где произошла фатальная ошибка. К сожалению, эти функции не будут работать внутри функции отключения.
В комментариях об этом ответе говорится чуть более подробно:
Не работает Функция выключения происходит после того, как стек был размотан. Нет стековой информации для сброса.
Есть ли способ обойти это, заставляя PHP хранить трассировку стека до полного завершения процесса, или мы должны принять это как данность из-за внутренних возможностей PHP?
4 ответа
Есть ли способ обойти это, заставляя PHP держать трассировку стека
Это довольно бессмысленно, когда вызывается зарегистрированная функция, все определенные вами функции возвращаются или удаляются из стека.
Если вам нужно знать, где находится ваш код, то вам нужно его кодировать.
Это очень дорогое решение. Я никогда не пользовалась register_tick_function()
или же tick
и я не уверен, работает ли он так, как ожидалось.
declare(ticks=1);
function tick_handler() {
global $backtrace;
$backtrace = debug_backtrace();
}
register_tick_function('tick_handler');
function shutdown() {
global $backtrace;
// do check if $backtrace contains a fatal error...
var_dump($backtrace);
}
register_shutdown_function('shutdown');
В расширении XDebug есть xdebug_get_function_stack()
функция.
Этот работает аналогично внутреннему PHP debug_backtrace()
, но сохраняет след даже в обработчике выключения.
Тем не менее, вы не получите точную точку выхода, только последняя выполненная функция до выключения (инициируется die()
/ exit()
вызов или ошибка).
Это, конечно, подходит только для среды разработки.
По моему опыту, функция выключения запускается с чистого стека и не имеет доступа к "оригинальному" стеку (так как он больше не существует).
К сожалению, нет никакого способа сохранить этот оригинальный стек.
Внутри вашей зарегистрированной функции выключения вы можете получить обратный след с помощью функции http://www.php.net/error_get_last. У меня работает в PHP7.