Распечатать стек вызовов PHP


257

Я ищу способ напечатать стек вызовов в PHP.

Бонусные баллы, если функция очищает буфер ввода-вывода.



12
... но эти ответы лучше.
Бен

Ответы:


123

Если вы хотите создать обратную трассировку, вы ищете debug_backtraceи / или debug_print_backtrace.


Первый, например, даст вам массив, подобный этому (цитируя руководство) :

array(2) {
[0]=>
array(4) {
    ["file"] => string(10) "/tmp/a.php"
    ["line"] => int(10)
    ["function"] => string(6) "a_test"
    ["args"]=>
    array(1) {
      [0] => &string(6) "friend"
    }
}
[1]=>
array(4) {
    ["file"] => string(10) "/tmp/b.php"
    ["line"] => int(2)
    ["args"] =>
    array(1) {
      [0] => string(10) "/tmp/a.php"
    }
    ["function"] => string(12) "include_once"
  }
}


Очевидно, они не очистят буфер ввода-вывода, но вы можете сделать это самостоятельно, с помощью flushи / или ob_flush.

(см. страницу руководства первой, чтобы узнать, почему "и / или" ;-))


7
это регулярно заставляет мой PHP исчерпать память. Я рекомендую решение Тобиаса.
Пиди

Если вам трудно читать / понимать, я также рекомендую решение
Тобиаса

1
@peedee все, что требуется, это предоставить один из необязательных DEBUG_BACKTRACE_IGNORE_ARGSпараметров; что делает их функционально эквивалентными(new \Exception())->getTraceAsString()

567

Более читабельно, чем debug_backtrace():

$e = new \Exception;
var_dump($e->getTraceAsString());

#2 /usr/share/php/PHPUnit/Framework/TestCase.php(626): SeriesHelperTest->setUp()
#3 /usr/share/php/PHPUnit/Framework/TestResult.php(666): PHPUnit_Framework_TestCase->runBare()
#4 /usr/share/php/PHPUnit/Framework/TestCase.php(576): PHPUnit_Framework_TestResult->run(Object(SeriesHelperTest))
#5 /usr/share/php/PHPUnit/Framework/TestSuite.php(757): PHPUnit_Framework_TestCase->run(Object(PHPUnit_Framework_TestResult))
#6 /usr/share/php/PHPUnit/Framework/TestSuite.php(733): PHPUnit_Framework_TestSuite->runTest(Object(SeriesHelperTest), Object(PHPUnit_Framework_TestResult))
#7 /usr/share/php/PHPUnit/TextUI/TestRunner.php(305): PHPUnit_Framework_TestSuite->run(Object(PHPUnit_Framework_TestResult), false, Array, Array, false)
#8 /usr/share/php/PHPUnit/TextUI/Command.php(188): PHPUnit_TextUI_TestRunner->doRun(Object(PHPUnit_Framework_TestSuite), Array)
#9 /usr/share/php/PHPUnit/TextUI/Command.php(129): PHPUnit_TextUI_Command->run(Array, true)
#10 /usr/bin/phpunit(53): PHPUnit_TextUI_Command::main()
#11 {main}"

50
Черт, это намного лучше, почему они не могли сделать это выводом по умолчанию для debug_print_backtrace ()? Можно было бы добавить логический параметр «returnTrace» для тех, кто хочет, чтобы он был в переменной, а не отражался, и это было бы идеально!
Юрчик

1
Я не знаю, сколько месяцев я пытался понять, как это сделать, никогда не думал, что это сработает
WojonsTech 22.10.13

Это решение также требует меньше памяти, чем захват вывода debug_backtrace () в виде массива и последующая печать с использованием print_r (), что я и делал, пока не увидел это!
Питер

5
Я искал способ ограничения, debug_backtraceчтобы вернуть только первый уровень в трассировке стека - это решение работает для меня. Спасибо!
ankr

3
@Andrew print_rсохранит все сообщения.
mopo922

41

Для записи трассировки

$e = new Exception;
error_log(var_export($e->getTraceAsString(), true));

Спасибо @Tobiasz


35

Backtrace сбрасывает много мусора, который вам не нужен. Это занимает очень много времени, трудно читать. Все, что вы обычно когда-либо хотите, это "что называется, откуда?" Вот простое решение статической функции. Я обычно помещаю его в класс под названием «отладка», который содержит все мои вспомогательные функции отладки.

class debugUtils {
    public static function callStack($stacktrace) {
        print str_repeat("=", 50) ."\n";
        $i = 1;
        foreach($stacktrace as $node) {
            print "$i. ".basename($node['file']) .":" .$node['function'] ."(" .$node['line'].")\n";
            $i++;
        }
    } 
}

Вы называете это так:

debugUtils::callStack(debug_backtrace());

И это производит вывод как это:

==================================================
 1. DatabaseDriver.php::getSequenceTable(169)
 2. ClassMetadataFactory.php::loadMetadataForClass(284)
 3. ClassMetadataFactory.php::loadMetadata(177)
 4. ClassMetadataFactory.php::getMetadataFor(124)
 5. Import.php::getAllMetadata(188)
 6. Command.php::execute(187)
 7. Application.php::run(194)
 8. Application.php::doRun(118)
 9. doctrine.php::run(99)
 10. doctrine::include(4)
==================================================


33

Странно, что никто так не писал

debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);

Это на самом деле печатает обратную трассировку без мусора - только то, что метод был вызван и где.


2
Действительно, действительно эквивалентно основному проголосовавшему решению и короче. Спасибо
brunetton

9

Если вам нужна трассировка стека, которая очень похожа на то, как php форматирует трассировку стека исключений, используйте эту функцию, которую я написал:

function debug_backtrace_string() {
    $stack = '';
    $i = 1;
    $trace = debug_backtrace();
    unset($trace[0]); //Remove call to this function from stack trace
    foreach($trace as $node) {
        $stack .= "#$i ".$node['file'] ."(" .$node['line']."): "; 
        if(isset($node['class'])) {
            $stack .= $node['class'] . "->"; 
        }
        $stack .= $node['function'] . "()" . PHP_EOL;
        $i++;
    }
    return $stack;
} 

Это вернет трассировку стека в следующем формате:

#1 C:\Inetpub\sitename.com\modules\sponsors\class.php(306): filePathCombine()
#2 C:\Inetpub\sitename.com\modules\sponsors\class.php(294): Process->_deleteImageFile()
#3 C:\Inetpub\sitename.com\VPanel\modules\sponsors\class.php(70): Process->_deleteImage()
#4 C:\Inetpub\sitename.com\modules\sponsors\process.php(24): Process->_delete() 

2
или просто$e = new Exception; echo $e->getTraceAsString();
Брэд Кент

Брэд, это решение не удаляет последний элемент из трассировки стека, поэтому вы не показываете элемент трассировки, вызванный новым исключением
TroySteven



4

phptrace - отличный инструмент для печати стека PHP в любое время, когда вам нужно, без установки каких-либо расширений.

Существуют две основные функции phptrace: во-первых, стек вызовов PHP для печати, который не требует установки чего-либо, во-вторых, отслеживание потоков выполнения php, для которых необходимо установить расширение, которое оно предоставляет.

следующим образом:

$ ./phptrace -p 3130 -s             # phptrace -p <PID> -s
phptrace 0.2.0 release candidate, published by infra webcore team
process id = 3130
script_filename = /home/xxx/opt/nginx/webapp/block.php
[0x7f27b9a99dc8]  sleep /home/xxx/opt/nginx/webapp/block.php:6
[0x7f27b9a99d08]  say /home/xxx/opt/nginx/webapp/block.php:3
[0x7f27b9a99c50]  run /home/xxx/opt/nginx/webapp/block.php:10 

Есть ли версия для Windows?
Джонни

Мне нравится адрес памяти, показанный здесь .. Это может быть полезно
Тайлер Майлз

3

Используйте, debug_backtraceчтобы получить обратную информацию о том, какие функции и методы были вызваны и какие файлы были включены, что привело к точке, где debug_backtraceбыл вызван.





1

Решение Walltearer превосходно, особенно если оно заключено в тег «pre»:

<pre>
<?php debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); ?>
</pre>

- который излагает звонки на отдельных линиях, аккуратно пронумерованных


0

Я адаптировал ответ Дона Бриггса выше, чтобы использовать внутреннюю регистрацию ошибок вместо общедоступной печати, которая может быть вашей большой проблемой при работе на живом сервере. Кроме того, добавлено еще несколько модификаций, таких как опция, включающая полный путь к файлу вместо базового имени (потому что могут быть файлы с одинаковыми именами в разных путях), а также (для тех, кому это требуется) вывод полного стека узлов:

class debugUtils {
    public static function callStack($stacktrace) {
        error_log(str_repeat("=", 100));
        $i = 1;
        foreach($stacktrace as $node) {
            // uncomment next line to debug entire node stack
            // error_log(print_r($node, true));
            error_log( $i . '.' . ' file: ' .$node['file'] . ' | ' . 'function: ' . $node['function'] . '(' . ' line: ' . $node['line'] . ')' );
            $i++;
        }
        error_log(str_repeat("=", 100));
    } 
}

// call debug stack
debugUtils::callStack(debug_backtrace());
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.