W3docs

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-трассировки перед деплоем в продакшен.

Практика

Практика
Какова основная цель функции debug_print_backtrace() в PHP?
Какова основная цель функции debug_print_backtrace() в PHP?
Was this page helpful?