Трассировка в PHP: пошаговое руководство по отладке

Раздел: Обработка ошибок PHP -> Отладка

Основные подходы к трассировке PHP

Трассировка (trace) в PHP позволяет отслеживать последовательность вызовов функций, анализировать ошибки и находить узкие места в коде. В зависимости от задачи используются разные методы: от встроенных функций до профессиональных инструментов. Ниже рассмотрены наиболее эффективные и популярные варианты.

Как выполнять глубокую трассировку с помощью Xdebug?

Xdebug - расширение PHP, предоставляющее мощные средства отладки. Оно может генерировать файлы трассировки с подробной информацией о каждом вызове, времени выполнения и использовании памяти. Это наиболее эффективное решение для анализа производительности и ошибок в сложных проектах.

Установка и настройка

Установите Xdebug через менеджер пакетов (PECL, apt, brew) или скомпилируйте. После установки добавьте в php.ini:

zend_extension=xdebug.so
xdebug.mode=debug,trace
xdebug.start_with_request=yes
xdebug.output_dir=/tmp/xdebug
xdebug.trace_output_name=trace.%s

проверка php (проверка установки php)

Теперь каждый запрос будет создавать файл трассировки в указанной папке. Для ручного управления используйте функции:

xdebug_start_trace('/tmp/trace.xt');
// выполняемый код
xdebug_stop_trace();

Index php log (логирование в php)

Файл содержит timestamp, уровень вложенности, имя функции, файл и строку, переданные аргументы (ограниченные по умолчанию 4 уровнями).

Типичные проблемы: неправильная конфигурация режима, отсутствие записи в output_dir из-за прав доступа, переполнение диска при большом количестве запросов. Решение - проверять настройки в phpinfo() и очищать папку с трассами.

Как получить стек вызовов при помощи debug_backtrace?

Функция debug_backtrace() возвращает массив с информацией о стеке вызовов на момент её выполнения. Это лёгкий способ трассировки без установки расширений.

function first() { second(); }
function second() { third(); }
function third() {
    $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
    print_r($trace);
}
first();

Php warning session start (предупреждение сессии)

Результат содержит ключи: file, line, function, class, type. С флагом DEBUG_BACKTRACE_PROVIDE_OBJECT также возвращаются объекты. Однако при глубоких стеках (рекурсия) метод может потреблять много памяти.

Ошибки: при использовании без лимита глубины возможен infinite loop при рекурсивных вызовах. В production следует ограничить глубину через настройки xdebug.max_nesting_level или явно прерывать по счётчику.

Как трассировать последнюю ошибку с помощью error_get_last и пользовательского обработчика?

Встроенная функция error_get_last() возвращает информацию о последней произошедшей ошибке. В сочетании с пользовательским обработчиком можно записать полную трассировку.

set_error_handler(function($severity, $message, $file, $line) {
    $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
    $log = "Ошибка: $message в $file:$line\n";
    $log .= "Стек:\n" . print_r($trace, true);
    error_log($log, 3, '/tmp/errors.log');
});
trigger_error('Тестовая ошибка', E_USER_NOTICE);

Php view source (просмотр исходного кода php)

Такой подход позволяет записывать трассу в лог без сторонних инструментов. Недостаток - обработчик не перехватывает фатальные ошибки (E_ERROR, E_PARSE), для них нужен register_shutdown_function.

Проблемы: если обработчик сам вызывает ошибку, возникает бесконечная рекурсия. Решение - проверять уровень ошибок и временно отключать обработчик для внутренних операций.

Как использовать библиотеку Whoops для отображения трассировки?

Whoops - это библиотека для отладки, которая красиво отображает ошибки с полным стеком вызовов. Она подходит для разработки и может быть легко интегрирована в любой проект.

require 'vendor/autoload.php';
$whoops = new \Whoops\Run;
$whoops->pushHandler(new \Whoops\Handler\PrettyPageHandler);
$whoops->register();
// далее любой код вызовет красивую страницу с трассой

Whoops поддерживает черный список функций, отображение фреймов, поиск по стеку. Для production обычно используют PlainTextHandler или логирование.

Типичные ошибки: несовместимость с другими обработчиками ошибок, дублирование вывода. Решение - регистрировать Whoops до других обработчиков или использовать prependHandler.

- Php get null (ошибка получения get параметров)
- Fail get contents php (ошибка при использовании file_get_contents)
- Php get trace (получение стека вызовов в php)

Расширенные примеры с различными сценариями трассировки в PHP.

Пример 1: debug_backtrace в рекурсивной функции

Пример
function factorial($n, $depth = 0) {
    if ($n <= 1) {
        $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 10);
        echo "Достигнут базовый случай. Глубина стека: $depth\n";
        array_shift($trace); // убираем текущий вызов
        foreach ($trace as $i => $call) {
            echo "#$i {$call['function']}() вызвана в {$call['file']}:{$call['line']}\n";
        }
        return 1;
    }
    return $n * factorial($n - 1, $depth + 1);
}
factorial(5);

Результат (сокращённый):

Достигнут базовый случай. Глубина стека: 4
#0 factorial() вызвана в /var/www/test.php:11
#1 factorial() вызвана в /var/www/test.php:11
#2 factorial() вызвана в /var/www/test.php:11
#3 factorial() вызвана в /var/www/test.php:11
#4 {main}() вызвана в /var/www/test.php:14

Пример 2: Xdebug trace с аргументами и временем

Пример
xdebug_start_trace('/tmp/trace.html', XDEBUG_TRACE_HTML);

function slowFunction($data) {
    usleep(100000); // имитация работы
    return substr($data, 0, 10);
}

$result = slowFunction('Длинная строка для теста');
$x = [1,2,3];
array_map(function($v) { return $v*2; }, $x);

xdebug_stop_trace();

Содержимое файла trace.html (открывается в браузере как таблица):

TRACE START [2025-03-15 10:00:00]
  0.0010 410248  +strlen → 20
  0.0012 410312  +slowFunction( 'Длинная строка для теста' ) /var/www/test.php:6
  0.1003 410400  -slowFunction → 'Длинная ст'  (0.0991 sec)
  0.1004 410480  +array_map( Closure, array(1,2,3) ) /var/www/test.php:9
  0.1005 410512  -array_map → array(2,4,6)
TRACE END   [2025-03-15 10:00:00.1006]

Видно время выполнения каждой функции и размер используемой памяти (в байтах).

Пример 3: Трассировка фатальных ошибок через register_shutdown_function

Пример
register_shutdown_function(function() {
    $error = error_get_last();
    if ($error && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])) {
        $trace = "Фатальная ошибка: {$error['message']} в {$error['file']}:{$error['line']}\n";
        $trace .= "Стек на момент ошибки:\n";
        // debug_backtrace может не работать, используем xdebug_get_function_stack
        if (function_exists('xdebug_get_function_stack')) {
            $stack = xdebug_get_function_stack();
            foreach (array_reverse($stack) as $frame) {
                $trace .= "{$frame['function']}() в {$frame['file']}:{$frame['line']}\n";
            }
        }
        file_put_contents('/tmp/fatal_error.log', $trace, FILE_APPEND);
    }
});

// вызов несуществующего метода для генерации E_ERROR
$obj = new stdClass;
$obj->undefinedMethod();

Лог-файл получит трассу, показывающую последовательность вызовов до фатальной ошибки (если доступен xdebug_get_function_stack).

Пример 4: Трассировка с помощью phptrace (CLI)

Инструмент phptrace позволяет трассировать работающий PHP-процесс без изменения кода.

Пример
# Запускаем PHP скрипт с PID 1234
sudo phptrace -p 1234 -o /tmp/phptrace.log
# Или сразу для выполнения:
phptrace -e 'file_get_contents("/etc/passwd")'

Вывод содержит дату, время, функцию и аргументы (частично). Этот метод полезен для анализа уже работающих процессов.

Трассировка в PHP - comments

En
Php trace (php)