Imprimer la pile d'appels PHP


Réponses:


123

Si vous souhaitez générer une trace, vous recherchez debug_backtraceet / ou debug_print_backtrace.


Le premier vous donnera, par exemple, un tableau comme celui-ci (en citant le manuel) :

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


Apparemment, ils ne videront pas le tampon d'E / S, mais vous pouvez le faire vous-même, avec flushet / ou ob_flush.

(voir la page de manuel du premier pour savoir pourquoi le "et / ou" ;-))


7
cela fait régulièrement manquer de mémoire à mon php. Je recommande la solution de Tobiasz.
peedee

Si vous avez du mal à lire / comprendre, je recommande également la solution de
Tobiasz

1
@peedee, il suffit de fournir l'un des DEBUG_BACKTRACE_IGNORE_ARGSparamètres facultatifs ; ce qui les rend fonctionnellement équivalents à(new \Exception())->getTraceAsString()

567

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

50
Merde, c'est tellement mieux, pourquoi ne pourraient-ils pas en faire la sortie par défaut pour debug_print_backtrace ()? Aurait pu ajouter un paramètre booléen "returnTrace" pour ceux qui le veulent dans une variable, pas en écho, et ça aurait été parfait!
jurchiks

1
Je ne sais pas combien de mois j'ai essayé de comprendre comment faire ça, je n'ai jamais pensé que ça marcherait
WojonsTech

Cette solution semble également prendre moins de mémoire que de capturer la sortie de debug_backtrace () sous forme de tableau, puis de l'imprimer à l'aide de print_r (), ce que j'avais fait jusqu'à ce que je voie cela!
Peter

5
Je cherchais un moyen de limiter debug_backtracepour ne renvoyer que le premier niveau dans le stacktrace - cette solution fait le travail pour moi. Je vous remercie!
ankr

3
@Andrew print_rconservera tous les messages.
mopo922

41

Pour enregistrer la trace

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

Merci @Tobiasz


35

Backtrace vide un tas de déchets dont vous n'avez pas besoin. Cela prend très longtemps, difficile à lire. Tout ce que vous voulez habituellement, c'est "ce qui a appelé quoi d'où?" Voici une solution de fonction statique simple. Je le mets généralement dans une classe appelée «débogage», qui contient toutes mes fonctions utilitaires de débogage.

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

Vous l'appelez comme ceci:

debugUtils::callStack(debug_backtrace());

Et il produit une sortie comme celle-ci:

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

Étrange que personne n'ait publié de cette façon:

debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);

Cela imprime en fait la trace sans les ordures - juste quelle méthode a été appelée et où.


2
En effet, vraiment équivalent à la principale solution votée, et plus court. Merci
brunetton

9

Si vous voulez une trace de pile qui ressemble beaucoup à la façon dont php formate la trace de pile d'exception, utilisez cette fonction, j'ai écrit:

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

Cela retournera une trace de pile formatée comme ceci:

#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
ou tout simplement$e = new Exception; echo $e->getTraceAsString();
Brad Kent

Brad, cette solution ne supprime pas le dernier élément de la trace de la pile, donc vous n'affichez pas l'élément de trace provoqué par la nouvelle exception
TroySteven

8
var_dump(debug_backtrace());

Est-ce que ça fait ce que vous voulez?



4

phptrace est un excellent outil pour imprimer la pile PHP à tout moment quand vous le souhaitez sans installer d'extensions.

Il y a deux fonctions principales de phptrace: premièrement, imprimer la pile d'appels de PHP qui n'a pas besoin d'installer quoi que ce soit, deuxièmement, tracer les flux d'exécution de php qui doivent installer l'extension qu'il fournit.

comme suit:

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

Existe-t-il une version Windows?
johnny

J'aime que l'adresse mémoire soit indiquée ici .. Cela peut être utile
Tyler Miles

3

Utilisez debug_backtracepour obtenir une trace des fonctions et méthodes qui ont été appelées et des fichiers qui ont été inclus et qui ont conduit au point où ils debug_backtraceont été appelés.





1

La solution de Walltearer est excellente, en particulier si elle est enfermée dans une étiquette «pré»:

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

- qui établit les appels sur des lignes distinctes, soigneusement numérotées


0

J'ai adapté la réponse de Don Briggs ci-dessus pour utiliser la journalisation des erreurs internes au lieu de l'impression publique, ce qui peut être votre grande préoccupation lorsque vous travaillez sur un serveur en direct. En outre, quelques modifications supplémentaires comme l'option pour inclure le chemin de fichier complet au lieu du nom de base (car il pourrait y avoir des fichiers avec le même nom dans des chemins différents) et également (pour ceux qui en ont besoin) une sortie de pile de nœuds complète:

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());
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.