Stampa stack chiamate PHP


Risposte:


123

Se si desidera generare una backtrace, si sta cercando debug_backtracee / o debug_print_backtrace.


Il primo, ad esempio, ti offrirà un array come questo (citando il manuale) :

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


Apparentemente non svuoteranno il buffer I / O, ma puoi farlo tu stesso, con flushe / o ob_flush.

(vedere la pagina del manuale del primo per scoprire perché "e / o" ;-))


7
questo fa regolarmente esaurire la memoria del mio php. Raccomando la soluzione di Tobiasz.
Peedee,

Se hai difficoltà a leggere / capire, consiglio anche la soluzione di Tobiasz
ViliusL

1
@peedee è sufficiente fornire uno dei DEBUG_BACKTRACE_IGNORE_ARGSparametri opzionali ; che li rende funzionalmente equivalenti a(new \Exception())->getTraceAsString()

566

Più leggibile di 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
Dannazione, è molto meglio, perché non potevano renderlo l'output predefinito per debug_print_backtrace ()? Avrebbe potuto aggiungere un parametro booleano "returnTrace" per coloro che lo desiderano in una variabile, non riecheggiato, e sarebbe stato perfetto!
Jurchiks,

1
Non so da quanti mesi ho cercato di capire come fare che non avrei mai pensato che avrebbe funzionato
WojonsTech

Questa soluzione sembra anche occupare meno memoria che catturare l'output di debug_backtrace () come un array e quindi stamparlo usando print_r (), che è quello che avevo fatto fino a quando non l'ho visto!
Peter,

5
Stavo cercando un modo per limitare debug_backtracesolo il ritorno al primo livello nello stacktrace: questa soluzione fa il lavoro per me. Grazie!
aprile

3
@Andrew print_rconserverà tutti i messaggi.
mopo922,

41

Per registrare la traccia

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

Grazie @Tobiasz


35

Backtrace scarica un sacco di immondizia che non ti serve. Ci vuole molto tempo, difficile da leggere. Tutto ciò che di solito volete è "ciò che ha chiamato cosa da dove?" Ecco una semplice soluzione con funzioni statiche. Di solito lo inserisco in una classe chiamata 'debug', che contiene tutte le mie funzioni di utilità di debug.

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

Lo chiami così:

debugUtils::callStack(debug_backtrace());

E produce output in questo modo:

==================================================
 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

Strano che nessuno abbia pubblicato in questo modo:

debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);

Questo in realtà stampa backtrace senza immondizia - solo quale metodo è stato chiamato e dove.


2
Anzi, è davvero equivalente alla soluzione votata principale e più breve. Grazie
Brunetton il

9

Se vuoi una traccia dello stack che assomigli molto al modo in cui php formatta la traccia dello stack delle eccezioni rispetto all'uso di questa funzione, ho scritto:

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

Ciò restituirà una traccia dello stack formattata in questo modo:

#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
o semplicemente$e = new Exception; echo $e->getTraceAsString();
Brad Kent,

Brad, quella soluzione non rimuove l'ultimo elemento dalla traccia dello stack in modo da non mostrare l'elemento di traccia causato dalla nuova eccezione
TroySteven

8
var_dump(debug_backtrace());

Fa quello che vuoi?



4

phptrace è un ottimo strumento per stampare lo stack PHP ogni volta che vuoi senza installare alcuna estensione.

Esistono due funzioni principali di phptrace: in primo luogo, stampare lo stack di chiamate di PHP che non ha bisogno di installare nulla, in secondo luogo, tracciare i flussi di esecuzione di php che devono installare l'estensione fornita.

come segue:

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

Esiste una versione di Windows?
johnny,

Mi piace che l'indirizzo di memoria sia mostrato qui .. Questo può essere utile
Tyler Miles,

3

Utilizzare debug_backtraceper ottenere una traccia indietro di quali funzioni e metodi sono stati chiamati e quali file sono stati inclusi che hanno portato al punto in cui debug_backtraceè stato chiamato.





1

La soluzione di Walltearer è eccellente, in particolare se racchiusa in un tag 'pre':

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

- che stabilisce le chiamate su linee separate, ordinatamente numerate


0

Ho adattato la risposta di Don Briggs sopra per utilizzare la registrazione degli errori interna anziché la stampa pubblica, che potrebbe essere la tua principale preoccupazione quando si lavora su un server live. Inoltre, sono state aggiunte alcune ulteriori modifiche come l'opzione per includere il percorso completo del file anziché il nome di base (perché, potrebbero esserci file con lo stesso nome in percorsi diversi) e anche (per coloro che lo richiedono) un output completo dello stack dei nodi:

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());
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.