Imprimir pila de llamadas PHP

Respuestas:

123

Si desea generar una traza inversa, está buscando debug_backtracey / o debug_print_backtrace.


El primero, por ejemplo, te dará una matriz como esta (citando el manual) :

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


Aparentemente no vaciarán el búfer de E / S, pero puede hacerlo usted mismo, con flushy / o ob_flush.

(Consulte la página del manual de la primera para averiguar por qué "y / o" ;-)

Pascal MARTIN
fuente
77
esto regularmente hace que mi php se quede sin memoria. Recomiendo la solución de Tobiasz.
peedee
Si le resulta difícil de leer / comprender, también recomiendo la solución de
Tobiasz
1
@peedee todo lo que se necesita es proporcionar uno de los DEBUG_BACKTRACE_IGNORE_ARGSparámetros opcionales ; eso los hace funcionalmente equivalentes a(new \Exception())->getTraceAsString()
567

Más legible que 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}"
Tobias Cudnik
fuente
50
Maldición, esto es mucho mejor, ¿por qué no podrían hacer que esta sea la salida predeterminada para debug_print_backtrace ()? Podría haber agregado un parámetro booleano "returnTrace" para aquellos que lo desean en una variable, no repetida, ¡y hubiera sido perfecto!
jurchiks
1
No sé cuántos meses i estado tratando de encontrar la manera de hacer que nunca pensó que funcionaría
WojonsTech
¡Esta solución también parece tomar menos memoria que capturar la salida de debug_backtrace () como una matriz y luego imprimirla usando print_r (), que es lo que había estado haciendo hasta que vi esto!
Peter
55
Estaba buscando una forma de limitar debug_backtracepara devolver solo el primer nivel en el stacktrace: esta solución hace el trabajo por mí. ¡Gracias!
ankr
3
@ Andrew print_rretendrá todos los mensajes.
mopo922
41

Para registrar el rastro

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

Gracias @Tobiasz

Sydwell
fuente
35

Backtrace arroja una gran cantidad de basura que no necesita. Se tarda mucho, es difícil de leer. Todo lo que siempre quieres es "¿cómo se llama qué de dónde?" Aquí hay una solución simple de función estática. Normalmente lo pongo en una clase llamada 'depuración', que contiene todas mis funciones de utilidad de depuración.

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 llamas así:

debugUtils::callStack(debug_backtrace());

Y produce resultados como este:

==================================================
 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)
==================================================
Don Briggs
fuente
33

Es extraño que nadie haya publicado de esta manera:

debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);

Esto realmente imprime la traza inversa sin la basura, solo qué método se llamó y dónde.

AbstractVoid
fuente
2
De hecho, realmente equivalente a la solución principal votada, y más breve. Gracias
brunetton
9

Si desea un seguimiento de la pila que se parece mucho a cómo php formatea el seguimiento de la pila de excepción que usar esta función, escribí:

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

Esto devolverá una traza de pila formateada así:

#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() 
TroySteven
fuente
2
o simplemente$e = new Exception; echo $e->getTraceAsString();
Brad Kent
Brad, esa solución no elimina el último elemento del seguimiento de la pila, por lo que no muestra el elemento de seguimiento causado por la nueva Excepción
TroySteven
8
var_dump(debug_backtrace());

¿Eso hace lo que quieres?

entintado
fuente
4

phptrace es una gran herramienta para imprimir la pila PHP en cualquier momento cuando lo desee sin instalar ninguna extensión.

Hay dos funciones principales de phptrace: primero, imprimir la pila de llamadas de PHP que no necesita instalar nada, segundo, rastrear los flujos de ejecución de php que necesitan instalar la extensión que proporciona.

como sigue:

$ ./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 
Renovar
fuente
¿Hay una versión de Windows?
Johnny
Me gusta la dirección de memoria que se muestra aquí ... Esto puede ser útil
Tyler Miles
3

Se utiliza debug_backtracepara obtener un seguimiento de las funciones y métodos que se han llamado y qué archivos se han incluido que condujeron al punto donde debug_backtracese ha llamado.

Gumbo
fuente
1

debug_backtrace()

pix0r
fuente
1

La solución de Walltearer es excelente, particularmente si está encerrada en una etiqueta 'pre':

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

- que establece las llamadas en líneas separadas, perfectamente numeradas

Geoff Kendall
fuente
0

He adaptado la respuesta de Don Briggs anterior para usar el registro de errores internos en lugar de la impresión pública, lo que puede ser su gran preocupación cuando trabaje en un servidor en vivo. Además, se agregaron algunas modificaciones más, como la opción de incluir la ruta completa del archivo en lugar del nombre básico (porque podría haber archivos con el mismo nombre en diferentes rutas) y también (para aquellos que lo requieran) una salida completa de la pila de nodos:

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());
dev101
fuente