Print PHP Call Stack
Asked Answered
S

16

333

I'm looking for a way to print the call stack in PHP.

Bonus points if the function flushes the IO buffer.

Stellular answered 14/9, 2009 at 18:22 Comment(3)
possible duplicate of How can I get PHP to produce a backtrace upon errors?Bingo
...but these responses are better.Supranational
if it is ordered by quality, then that thread is the duplicated one :DDendro
C
144

If you want to generate a backtrace, you are looking for debug_backtrace and/or debug_print_backtrace.


The first one will, for instance, get you an array like this one (quoting the 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"
  }
}


They will apparently not flush the I/O buffer, but you can do that yourself, with flush and/or ob_flush.

(see the manual page of the first one to find out why the "and/or" ;-) )

Crevasse answered 14/9, 2009 at 18:25 Comment(3)
this regularly makes my php run out of memory. I recommend Tobiasz' solution.Councilor
If you find it hard to read/understand, I also recommend Tobiasz' solutionExtract
@Councilor all it takes is to provide one of the optional DEBUG_BACKTRACE_IGNORE_ARGS parameter; that makes them functionally equivalent to (new \Exception())->getTraceAsString()Thread
K
720

More readable than 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}"
Kippy answered 12/8, 2011 at 11:27 Comment(11)
Damn, this is so much better, why couldn't they make this the default output for debug_print_backtrace()? Could have added a boolean parameter "returnTrace" for those who want it in a variable, not echoed, and it would have been perfect!Corettacorette
I dont know how many months i been trying to figure out how to do that never thought it would workPurify
This solution also appears to take less memory than capturing the output of debug_backtrace() as an array and then printing it using print_r(), which is what I had been doing until I saw this!Phytogenesis
I was looking for a way to limit debug_backtrace to only return the first level in the stacktrace - this solution does the work for me. Thank you!Anting
But seems to cut off the messagesRustie
@Rustie print_r will retain all the messages.Amelina
$e = new \Exception; echo "<pre>"; var_dump($e->getTraceAsString()); echo "</pre>"; die("test");Inquire
I dont understand this, where do I put my function or variable I want to backtrace?Appoggiatura
So much better and clean.Schifra
$call_stack = explode('#', $e->getTraceAsString()); to get it in a nice arrayPresumptuous
The best solution by far.Wichman
C
144

If you want to generate a backtrace, you are looking for debug_backtrace and/or debug_print_backtrace.


The first one will, for instance, get you an array like this one (quoting the 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"
  }
}


They will apparently not flush the I/O buffer, but you can do that yourself, with flush and/or ob_flush.

(see the manual page of the first one to find out why the "and/or" ;-) )

Crevasse answered 14/9, 2009 at 18:25 Comment(3)
this regularly makes my php run out of memory. I recommend Tobiasz' solution.Councilor
If you find it hard to read/understand, I also recommend Tobiasz' solutionExtract
@Councilor all it takes is to provide one of the optional DEBUG_BACKTRACE_IGNORE_ARGS parameter; that makes them functionally equivalent to (new \Exception())->getTraceAsString()Thread
O
55

Strange that noone posted this way:

debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);

This actually prints backtrace without the garbage - just what method was called and where.

O answered 14/3, 2016 at 17:17 Comment(2)
Indeed, really equivalent to the main voted solution, and shorter. ThanksItu
Where does this print to?Mammalian
D
50

To log the trace

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

Thanks @Tobiasz

Derward answered 24/10, 2011 at 15:30 Comment(0)
I
39

Backtrace dumps a whole lot of garbage that you don't need. It takes is very long, difficult to read. All you usuall ever want is "what called what from where?" Here is a simple static function solution. I usually put it in a class called 'debug', which contains all of my debugging utility functions.

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

You call it like this:

debugUtils::callStack(debug_backtrace());

And it produces output like this:

==================================================
 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)
==================================================
Institutor answered 13/12, 2011 at 23:9 Comment(2)
'file' and 'line' are not always present in $nodeCorrell
Why not add the parameters to those function calls? Class name is also available for class member functions. You could dd little more code, then out this on GitHub.Cairngorm
C
11

If you want a stack trace which looks very similar to how php formats the exception stack trace than use this function I wrote:

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

This will return a stack trace formatted like this:

#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() 
Cutcherry answered 15/3, 2013 at 18:46 Comment(2)
or just $e = new Exception; echo $e->getTraceAsString();Odonnell
Brad, that solution doesn't remove the last item from the stack trace so you don't show the trace item caused by the new ExceptionCutcherry
C
8
var_dump(debug_backtrace());

Does that do what you want?

Conglutinate answered 14/9, 2009 at 18:26 Comment(0)
T
6

See debug_print_backtrace. I guess you can call flush afterwards if you want.

Thyself answered 14/9, 2009 at 18:25 Comment(0)
D
6

phptrace is a great tool to print PHP stack anytime when you want without installing any extensions.

There are two major function of phptrace: first, print call stack of PHP which need not install anything, second, trace php execution flows which needs to install the extension it supplies.

as follows:

$ ./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 
Deherrera answered 6/1, 2015 at 9:55 Comment(2)
Is there a Windows version?Hermaherman
I like the memory address are shown here.. This can be helpfulGibe
M
6

If one is just interested in the files called - you can use the following:

print_r(array_column(debug_backtrace(),'file'));

Likewise you can replace file with a different key just to see that data.

Mccallum answered 13/10, 2021 at 14:9 Comment(0)
K
4

Walltearer's solution is excellent, particularly if enclosed in a 'pre' tag:

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

- which sets out the calls on separate lines, neatly numbered

Kynan answered 20/9, 2017 at 9:46 Comment(0)
N
3

Use debug_backtrace to get a backtrace of what functions and methods had been called and what files had been included that led to the point where debug_backtrace has been called.

Nikos answered 14/9, 2009 at 18:26 Comment(0)
F
2

please take a look at this utils class, may be helpful:

Usage:

<?php
/* first caller */
 Who::callme();

/* list the entire list of calls */
Who::followme();

Source class: https://github.com/augustowebd/utils/blob/master/Who.php

Foskett answered 11/3, 2016 at 18:36 Comment(0)
S
2

I have adapted Don Briggs's answer above to use internal error logging instead of public printing, which may be your big concern when working on a live server. Also, added few more modifications like option to include full file path instead of basic name (because, there could be files with same name in different paths), and also (for those who require it) a complete node stack output:

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());
Selfregulated answered 15/2, 2019 at 18:8 Comment(0)
K
1

debug_backtrace()

Klepht answered 14/9, 2009 at 18:25 Comment(0)
T
1

You might want to look into debug_backtrace, or perhaps debug_print_backtrace.

Thersathersites answered 14/9, 2009 at 18:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.