2009-09-14 22 views
201

Poszukuję sposobu na wydrukowanie stosu wywołań w PHP.Drukuj stos wywołań PHP

Punkty premiowe, jeśli funkcja opróżnia bufor we/wy.

+2

możliwy duplikat [Jak mogę uzyskać PHP do tworzenia śladu po błędach?] (http://stackoverflow.com/questions/1159216/how-can-i-get-php-to-produce-a-backtrace-upon-errors) – Gordon

+10

... ale te odpowiedzi są lepsze. – Ben

Odpowiedz

109

Jeśli chcesz wygenerować ślad, szukasz debug_backtrace i/lub debug_print_backtrace.


Pierwszy z nich, na przykład, Ci tablicę jak ten (podając instrukcję):

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" 
    } 
} 


Najwyraźniej nie będzie opróżnić bufor I/O, ale możesz to zrobić samodzielnie, z flush i/lub ob_flush .

(patrz instrukcja stronę pierwszego, aby dowiedzieć się, dlaczego „i/lub” ;-))

+5

to regularnie powoduje, że mój php wyczerpuje się pamięć. Polecam rozwiązanie Tobiasza. – peedee

3

Użyj debug_backtrace, aby uzyskać śledzenie, jakie funkcje i metody zostały wywołane oraz jakie pliki zostały dołączone, które doprowadziły do ​​punktu, w którym zostało wywołane debug_backtrace.

6
var_dump(debug_backtrace()); 

Czy to, co chcesz?

416

bardziej czytelny niż 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}" 
+4

Ahhhhh. Dzięki. – shaune

+28

Cholera, to jest o wiele lepsze, dlaczego nie mogą zrobić tego domyślnego wyjścia dla debug_print_backtrace()? Mogłoby dodać parametr boolowski "returnTrace" dla tych, którzy chcą go w zmiennej, a nie echo, i byłoby idealnie! – jurchiks

+0

Nie wiem, ile miesięcy próbowałem wymyślić, jak to zrobić, nigdy nie myślałem, że to zadziała – WojonsTech

32

Aby zalogować ślad

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

Dzięki @Tobiasz

27

Backtrace zrzuca mnóstwo śmieci, że nie trzeba. Potrzeba jest bardzo długa, trudna do odczytania. Wszystko, czego zwykle chcesz, to "co nazwałeś skąd?" Oto proste rozwiązanie funkcji statycznych. Zazwyczaj umieszczam go w klasie o nazwie "debugowanie", która zawiera wszystkie funkcje narzędzia do debugowania.

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++; 
     } 
    } 
} 

to nazwać tak:

debugUtils::callStack(debug_backtrace()); 

A produkuje wyjście tak:

================================================== 
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) 
================================================== 
+4

Stwórz element $ lub zmień nazwę elementu $ na $ node, big deal ... – Hejazzman

+1

['file' i 'line' nie zawsze są obecne w węźle $] (http://stackoverflow.com/a/6643478/ 210336) –

7

Jeśli chcesz ślad stosu, który wygląda bardzo podobnie do tego, jak formatuje php wyjątek śledzenie stosu niż użycie tej funkcji Napisałem:

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; 
} 

ten powróci ślad stosu sformatowany tak:

#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() 
3

phptrace jest doskonałym narzędziem do drukowania PHP stosu w każdej chwili kiedy chcesz bez instalowania żadnych rozszerzeń.

Istnieją dwie główne funkcje phptrace: po pierwsze, wywołaj stos wywołań PHP, który nie musi niczego instalować, po drugie, śledź przebieg wykonywania poleceń php, który musi zainstalować dostarczone rozszerzenie.

następująco:

$ ./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 
+0

Czy istnieje wersja systemu Windows? – johnny

18

dziwne, że nikt nie pisał w ten sposób:

debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); 

To faktycznie drukuje ślad wstecz bez śmieci - tylko jak została wywołana i gdzie.

+1

Rzeczywiście, naprawdę odpowiada to głównemu głosowanemu rozwiązaniu i krócej. Dzięki – brunetton

0

rozwiązanie Walltearer jest doskonała, szczególnie jeśli zamknięte w „pre” tagu:

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

- określający połączeń na oddzielnych liniach, starannie ponumerowane