debug_print_backtrace()
Функция debug_print_backtrace() выводит стек вызовов PHP прямо в вывод, помогая быстро найти путь выполнения до текущей строки.
Введение
Когда PHP-скрипт достигает ошибки, знать где она произошла зачастую недостаточно — нужно понять как программа туда попала: какая функция вызвала какую и в каком порядке. Эта цепочка вызовов называется стеком вызовов, и debug_print_backtrace() выводит его в готовом форматированном виде прямо в вывод. Это самый быстрый способ ответить на вопрос «какой путь привёл к этой строке?» без необходимости настраивать полноценный отладчик вроде Xdebug.
В этой главе рассматривается, что делает функция, её параметры, как читать её вывод, когда стоит к ней обращаться и чем она отличается от родственной функции debug_backtrace().
Что делает debug_print_backtrace()
debug_print_backtrace() обходит текущий стек вызовов — все активные вызовы функций и методов от верхнеуровневого скрипта до точки, в которой вы её вызвали, — и выводит читаемую трассировку. В отличие от debug_backtrace(), которая возвращает стек в виде array для последующей обработки или записи в лог, debug_print_backtrace() записывает форматированный текст напрямую в стандартный вывод и не возвращает ничего (void).
Используйте её, когда нужно просто увидеть путь вызовов прямо сейчас. Используйте debug_backtrace(), когда нужно обработать стек (отфильтровать фреймы, сохранить его, передать в логгер).
Синтаксис
debug_print_backtrace(int $options = 0, int $limit = 0): voidОба параметра необязательны:
$options— битовая маска, настраивающая вывод. Единственный флаг —DEBUG_BACKTRACE_IGNORE_ARGS, который убирает["params"](аргументы функции) из каждого фрейма. При значении0(по умолчанию) сводка аргументов включается.$limit— ограничивает количество выводимых фреймов стека.0(по умолчанию) означает отсутствие ограничения. Полезно при глубокой рекурсии, когда важны лишь несколько последних вызовов. Доступен начиная с PHP 5.4.0.
Базовое использование
Вызовите функцию из любого места скрипта. Рассмотрим три функции, вызывающие друг друга по очереди:
<?php
function a()
{
b();
}
function b()
{
c();
}
function c()
{
debug_print_backtrace();
}
a();
?>Здесь a() вызывает b(), которая вызывает c(), которая вызывает debug_print_backtrace(). Вывод — нумерованный список, самый последний вызов первым:
#0 /path/to/script.php(9): c()
#1 /path/to/script.php(4): b()
#2 /path/to/script.php(17): a()Читайте сверху вниз как «от внутреннего к внешнему»: фрейм #0 — место, где выполнялась c() (строка 9), #1 — её вызывающая функция b() (строка 4), #2 — исходная точка вызова a() (строка 17). В каждой строке показаны файл, номер строки в скобках и выполнявшаяся функция. Точка входа в скрипт не фигурирует как отдельный фрейм, поскольку у неё нет вызывающей стороны.
Ограничение количества фреймов
В рекурсивном или глубоко вложенном коде трассировка может быть очень длинной. Передайте $limit, чтобы оставить только ближайшие фреймы:
<?php
function countdown($n)
{
if ($n === 2) {
// Print just the two nearest frames.
debug_print_backtrace(0, 2);
return;
}
countdown($n - 1);
}
countdown(5);
?>Выводятся только два фрейма, хотя countdown() рекурсировала несколько раз:
#0 /path/to/script.php(9): countdown(2)
#1 /path/to/script.php(9): countdown(3)Скрытие аргументов
По умолчанию каждый фрейм показывает сводку переданных аргументов (как в примере выше с countdown(2)). Для конфиденциальных данных — паролей, токенов — или просто для уменьшения шума передайте DEBUG_BACKTRACE_IGNORE_ARGS:
<?php
function login($user, $password)
{
debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
}
login('admin', 'secret');
?>Фрейм по-прежнему отображается, но пароль в трассировку больше не попадает:
#0 /path/to/script.php(7): login()Когда использовать
- Отслеживание неожиданных вызовов — метод выполняется там, где вы этого не ожидали; вставьте трассировку в его начало, чтобы узнать, кто его запустил.
- Понимание устаревшего кода — быстрое построение карты потока вызовов без пошагового прохода в отладчике.
- Запись контекста при ошибках — хотя для логирования предпочтительнее
debug_backtrace(), чтобы захватить стек в виде строки и направить в файл (см. примечание ниже).
Подводные камни
- Функция выводит, а не возвращает. Результат нельзя присвоить переменной. Если стек нужен для логирования, используйте
debug_backtrace(). - Вывод идёт в ответ. При веб-запросе трассировка попадает в вывод страницы (или браузера), что может испортить HTML или JSON. Удаляйте такие вызовы перед выпуском в продакшен — или используйте альтернативу, дружественную к логированию.
- Захват в виде строки. Если всё же нужно форматирование
debug_print_backtrace()в логе, оберните вызов в буферизацию вывода:
<?php
function handler()
{
ob_start();
debug_print_backtrace();
$trace = ob_get_clean();
// $trace now holds the formatted backtrace as a string.
error_log($trace);
}
handler();
?>Связанные функции
debug_backtrace()— возвращает стек вызовов в виде array вместо его вывода.var_dump()иprint_r()— инспектирование значений переменных в процессе отладки.error_reporting()— управление тем, какие ошибки PHP выводит в принципе.
Заключение
debug_print_backtrace() — это однострочный способ вывести цепочку вызовов функций, приведшую к текущей точке PHP-скрипта. Необязательные параметры $options и $limit позволяют скрывать аргументы и обрезать длинные трассировки. Помните: функция выводит, а не возвращает — для программного доступа к стеку используйте debug_backtrace() и удаляйте print-трассировки перед деплоем в продакшен.