debug_backtrace

(PHP 4 >= 4.3.0, PHP 5)

debug_backtrace -- Generates a backtrace

说明

array debug_backtrace ( void )

debug_backtrace() generates a PHP backtrace.

返回值

Returns an associative array. The possible returned elements are as follows:

表格 1. Possible returned elements from debug_backtrace()

NameTypeDescription
functionstring The current function name. See also __FUNCTION__.
lineinteger The current line number. See also __LINE__.
filestring The current file name. See also __FILE__.
classstring The current class name. See also __CLASS__
typestring The current call type. If a method call, "->" is returned. If a static method call, "::" is returned. If a function call, nothing is returned.
argsarray If inside a function, this lists the functions arguments. If inside an included file, this lists the included file name(s).

范例

例子 1. debug_backtrace() example

<?php
// filename: a.php

function a_test($str)
{
    echo
"\nHi: $str";
    
var_dump(debug_backtrace());
}

a_test('friend');
?>

<?php
// filename: b.php
include_once '/tmp/a.php';
?>

Results similar to the following when executing /tmp/b.php:

Hi: friend
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"
  }
}


add a note add a note User Contributed Notes
icefragment at gmail dot com
24-Sep-2006 12:34
A simple python-like backtrace. Note that I don't recurse into arrays if they are passed as arguments to functions.

function backtrace()
{
   $bt = debug_backtrace();
  
   echo("<br /><br />Backtrace (most recent call last):<br /><br />\n");   
   for($i = 0; $i <= count($bt) - 1; $i++)
   {
       if(!isset($bt[$i]["file"]))
           echo("[PHP core called function]<br />");
       else
           echo("File: ".$bt[$i]["file"]."<br />");
      
       if(isset($bt[$i]["line"]))
           echo("&nbsp;&nbsp;&nbsp;&nbsp;line ".$bt[$i]["line"]."<br />");
       echo("&nbsp;&nbsp;&nbsp;&nbsp;function called: ".$bt[$i]["function"]);
      
       if($bt[$i]["args"])
       {
           echo("<br />&nbsp;&nbsp;&nbsp;&nbsp;args: ");
           for($j = 0; $j <= count($bt[$i]["args"]) - 1; $j++)
           {
               if(is_array($bt[$i]["args"][$j]))
               {
                   print_r($bt[$i]["args"][$j]);
               }
               else
                   echo($bt[$i]["args"][$j]);   
                          
               if($j != count($bt[$i]["args"]) - 1)
                   echo(", ");
           }
       }
       echo("<br /><br />");
   }
}
zmorris at mac dot com
21-Sep-2006 10:48
Hi, I got tired of using a trace( $message, __FILE__, __LINE__ ) function I made.  It forced me to include the file and line params (since php doesn't have macros) so I decided to make an alternative.

Simply call this new version using trace( 'my message' ); and it prints out a stack trace in a clearer way than the one stored in the debug_backtrace() array.  It handles traces from outside of functions, traces in nested functions, and traces in included files, and also displays the function in a way that can be pasted right back into your php code for faster testing!

NOTE - be sure to save your files with the correct line endings for the line numbers to work correctly, which for Mac OS X is unix.  You can get to this option in the popup menu in the toolbar at the top of each window in BBEdit.

<?php

function    print_var( $var )
{
   if(
is_string( $var ) )
       return(
'"'.str_replace( array("\x00", "\x0a", "\x0d", "\x1a", "\x09"), array('\0', '\n', '\r', '\Z', '\t'), $var ).'"' );
   else if(
is_bool( $var ) )
   {
       if(
$var )
           return(
'true' );
       else
           return(
'false' );
   }
   else if(
is_array( $var ) )
   {
      
$result = 'array( ';
      
$comma = '';
       foreach(
$var as $key => $val )
       {
          
$result .= $comma.print_var( $key ).' => '.print_var( $val );
          
$comma = ', ';
       }
      
$result .= ' )';
       return(
$result );
   }
  
   return(
var_export( $var, true ) );    // anything else, just let php try to print it
}

function   
trace( $msg )
{
   echo
"<pre>\n";
  
  
//var_export( debug_backtrace() ); echo "</pre>\n"; return;    // this line shows what is going on underneath
  
  
$trace = array_reverse( debug_backtrace() );
  
$indent = '';
  
$func = '';
  
   echo
$msg."\n";
  
   foreach(
$trace as $val)
   {
       echo
$indent.$val['file'].' on line '.$val['line'];
      
       if(
$func ) echo ' in function '.$func;
      
       if(
$val['function'] == 'include' ||
          
$val['function'] == 'require' ||
          
$val['function'] == 'include_once' ||
          
$val['function'] == 'require_once' )
          
$func = '';
       else
       {
          
$func = $val['function'].'(';
          
           if( isset(
$val['args'][0] ) )
           {
              
$func .= ' ';
              
$comma = '';
               foreach(
$val['args'] as $val )
               {
                  
$func .= $comma.print_var( $val );
                  
$comma = ', ';
               }
              
$func .= ' ';
           }
          
          
$func .= ')';
       }
      
       echo
"\n";
      
      
$indent .= "\t";
   }
  
   echo
"</pre>\n";
}

trace( 'error outside function' );

function   
test( $param1, $param2, $param3, $param4 )
{
  
trace( 'error in test()' );
}

test( 1.1, "param2\n", array( 1 => "a\n", "b\n" => 2 ), false );

?>
admin at sgssweb dot com
13-Aug-2006 05:30
Surprizingly, debug_backtrace() cannot aquire arguments from the function that is used as the second or later argument of a function.

<?php

function a($p) {
  
$backtrace = debug_backtrace();
  
   if (isset(
$backtrace[0]['args']))
      
var_export($backtrace[0]['args']);
   else
       echo
"Cannot aquire arguments";
   echo
"<br />";
  
   return
$p;
}

function
b($p1, $p2, $p3) {
   echo
"$p1, $p2, $p3";
}

// This outputs:
//    array ( 0 => 'First a', )
//    Cannot aquire arguments
//    Cannot aquire arguments
//    First a, Second a, Third a
b(a("First a"), a("Second a"), a("Third a"));

?>
tiwen at rpgame dot de
01-May-2006 04:25
Another debug output. This is a short function that does not display the args (sometimes password are in arguments ...) and shows the callstack clearly in a table. In most cases i don't need more ...

<?php
function dieDebug($sError)
{
   echo
"<hr /><div>".$sError."<br /><table border='1'>";
  
$sOut=""; $aCallstack=debug_backtrace();
  
   echo
"<thead><tr><th>file</th><th>line</th><th>function</th>".
      
"</tr></thead>";
   foreach(
$aCallstack as $aCall)
   {
       if (!isset(
$aCall['file'])) $aCall['file'] = '[PHP Kernel]';
       if (!isset(
$aCall['line'])) $aCall['line'] = '';

       echo
"<tr><td>{$aCall["file"]}</td><td>{$aCall["line"]}</td>".
          
"<td>{$aCall["function"]}</td></tr>";
   }
   echo
"</table></div><hr /></p>";
   die();
}
?>

To use it, simply do something like this:

<?php
if(...) dieDebug("another error found!");
?>
http://synergy8.com
14-Dec-2005 02:37
It should be noted that if an internal php function such as call_user_func in the backtrace, the 'file' and 'line' entries will not be set.

Most debug tracers will use these entries.  You should place a check to see if the key exists in the array before using this function.  Otherwise notices will be generated.

<?php

$arrTrace
= debug_backtrace();

foreach (
$arrTrace as $arr)
{
   if (!isset (
$arr['file']))
   {
      
$arr['file'] = '[PHP Kernel]';
   }

   if (!isset (
$arr['line']))
   {
      
$arr['line'] = '';
   }

  
// Do something
}

?>
tb
22-Jul-2005 02:18
I use this for debugging in my object oriented systems.  It allows me to output a debug/error/warning function with exact information about the location that the error was thrown, which is useful.  Check it:

<?php
abstract
class Debugger {
  
  
/**
     * Throw a debug message.
     */
  
abstract function debug($msg);
  
  
/**
     * Throw an error message.
     */
  
abstract function error($msg);
  
  
/**
     * Throw a warning message.
     */
  
abstract function warning($msg);
  
  
/**
     * Wrap a message with information about class, function, file and line
     * number and return it.
     */
  
protected function getMsg($msg) {
      
$bt = debug_backtrace();
      
      
// get class, function called by caller of caller of caller
      
$class = $bt[2]['class'];
      
$function = $bt[2]['function'];
      
      
// get file, line where call to caller of caller was made
      
$file = $bt[1]['file'];
      
$line = $bt[1]['line'];
      
      
// build & return the message
      
return "$class::$function: $msg in $file at $line";
   }
  
}
?>

Implement different debuggers for different scenarios (development, testing, production).  Each debugger extends Debugger; each of its methods (debug/error/warning) calls $this->getMsg($msg) to get a message with class, function, file, and line information.  Then it can either log it, email it, die with it, etc.

Then, just give each object (perhaps using a common superclass Object) a concrete debugger.  Then, from any object method, do something like:

<?php
class Foo extends Object {
     function
bar() {
        
$this->debugger->error("This is an error");
     }
}
?>

Which produces something like:

Foo::bar: This is an error in /some/file at X
diz at ysagoon dot com
24-Nov-2004 06:35
Ok as spagmoid already said, I just realized that my function has a similar bug than jlim's function.

So just add the following line:
if (is_array($bt['args']))
before line:
foreach ($bt['args'] as $a) {

This way you avoid the warning from being displayed.
diz at ysagoon dot com
24-Nov-2004 06:40
And here are my two cents for a useful and good looking backtrace function.

<?php

function backtrace()
{
  
$output = "<div style='text-align: left; font-family: monospace;'>\n";
  
$output .= "<b>Backtrace:</b><br />\n";
  
$backtrace = debug_backtrace();

   foreach (
$backtrace as $bt) {
      
$args = '';
       foreach (
$bt['args'] as $a) {
           if (!empty(
$args)) {
              
$args .= ', ';
           }
           switch (
gettype($a)) {
           case
'integer':
           case
'double':
              
$args .= $a;
               break;
           case
'string':
              
$a = htmlspecialchars(substr($a, 0, 64)).((strlen($a) > 64) ? '...' : '');
              
$args .= "\"$a\"";
               break;
           case
'array':
              
$args .= 'Array('.count($a).')';
               break;
           case
'object':
              
$args .= 'Object('.get_class($a).')';
               break;
           case
'resource':
              
$args .= 'Resource('.strstr($a, '#').')';
               break;
           case
'boolean':
              
$args .= $a ? 'True' : 'False';
               break;
           case
'NULL':
              
$args .= 'Null';
               break;
           default:
              
$args .= 'Unknown';
           }
       }
      
$output .= "<br />\n";
      
$output .= "<b>file:</b> {$bt['line']} - {$bt['file']}<br />\n";
      
$output .= "<b>call:</b> {$bt['class']}{$bt['type']}{$bt['function']}($args)<br />\n";
   }
  
$output .= "</div>\n";
   return
$output;
}

?>

And here's a sample of how the output looks like (the last call is on the top):

Backtrace:

file: 56 - /tmp/test.php
call: backtrace()

file: 53 - /tmp/test.php
call: test->bar(15.4, Array(4))

file: 61 - /tmp/test.php
call: test->test("making new object", True)

file: 65 - /tmp/test.php
call: foo(Resource(#2), Null)
ad-rotator.com
01-May-2004 12:11
To simply print out the file/function trace (chain of calls, file and line number before the error):

function getTrace() {
 $vDebug = debug_backtrace();
 $vFiles = array();
 for ($i=0;$i<count($vDebug);$i++) {
   // skip the first one, since it's always this func
   if ($i==0) { continue; }
   $aFile = $vDebug[$i];
   $vFiles[] = '('.basename($aFile['file']).':'.$aFile['line'].')';
 } // for
 $vTraceStr = implode(',',$vFiles);
}
spagmoid at yahoo dot NOSPAMcom
10-Dec-2003 03:47
ATTN: jlim#natsoft.com.my

Great function, but you have a few bugs.

At the line:
foreach($arr['args'] as $v)

Change it to:
$args = array();
if(!empty($arr['args'])) foreach($arr['args'] as $v)

And since line & file are not present in the array if calling from the error handler,

$Line = (isset($arr['line'])? $arr['line'] : "unknown");
$File = (isset($arr['file'])? $arr['file'] : "unknown");

and substitute accordingly.

Here's my version of it, alas with different formatting:
----------------------------------------

function DBG_GetBacktrace()
{
   $s = '';
   $MAXSTRLEN = 64;
  
   $s = '<pre align=left>';
   $traceArr = debug_backtrace();
   array_shift($traceArr);
   $tabs = sizeof($traceArr)-1;
   foreach($traceArr as $arr)
   {
       for ($i=0; $i < $tabs; $i++) $s .= ' &nbsp; ';
       $tabs -= 1;
       $s .= '<font face="Courier New,Courier">';
       if (isset($arr['class'])) $s .= $arr['class'].'.';
       $args = array();
       if(!empty($arr['args'])) foreach($arr['args'] as $v)
       {
           if (is_null($v)) $args[] = 'null';
           else if (is_array($v)) $args[] = 'Array['.sizeof($v).']';
           else if (is_object($v)) $args[] = 'Object:'.get_class($v);
           else if (is_bool($v)) $args[] = $v ? 'true' : 'false';
           else
           {
               $v = (string) @$v;
               $str = htmlspecialchars(substr($v,0,$MAXSTRLEN));
               if (strlen($v) > $MAXSTRLEN) $str .= '...';
               $args[] = "\"".$str."\"";
           }
       }
       $s .= $arr['function'].'('.implode(', ',$args).')</font>';
       $Line = (isset($arr['line'])? $arr['line'] : "unknown");
       $File = (isset($arr['file'])? $arr['file'] : "unknown");
       $s .= sprintf("<font color=#808080 size=-1> # line %4d, file: <a href=\"file:/%s\">%s</a></font>",
           $Line, $File, $File);
       $s .= "\n";
   }   
   $s .= '</pre>';
   return $s;
}
Fabian dot Kraetzer at gmx dot de
01-Sep-2003 09:18
I coded a function, too. Just call debug() evertime you think you could encounter an error:
<?
  
function debug()
   {
      
$debug_array = debug_backtrace();
      
$counter = count($debug_array);
       for(
$tmp_counter = 0; $tmp_counter != $counter; ++$tmp_counter)
       {
        
?>
          <table width="558" height="116" border="1" cellpadding="0" cellspacing="0" bordercolor="#000000">
           <tr>
             <td height="38" bgcolor="#D6D7FC"><font color="#000000">function <font color="#FF3300"><?
            
echo($debug_array[$tmp_counter]["function"]);?>(</font> <font color="#2020F0"><?
            
//count how many args a there
            
$args_counter = count($debug_array[$tmp_counter]["args"]);
            
//print them
            
for($tmp_args_counter = 0; $tmp_args_counter != $args_counter; ++$tmp_args_counter)
             {
                 echo(
$debug_array[$tmp_counter]["args"][$tmp_args_counter]);

                 if((
$tmp_args_counter + 1) != $args_counter)
                 {
                   echo(
", ");
                 }
                 else
                 {
                   echo(
" ");
                 }
             }
            
?></font><font color="#FF3300">)</font></font></td>
           </tr>
           <tr>
             <td bgcolor="#5F72FA"><font color="#FFFFFF">{</font><br>
               <font color="#FFFFFF">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;file: <?
              
echo($debug_array[$tmp_counter]["file"]);?></font><br>
               <font color="#FFFFFF">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;line: <?
              
echo($debug_array[$tmp_counter]["line"]);?></font><br>
               <font color="#FFFFFF">}</font></td>
           </tr>
         </table>
         <?
        
if(($tmp_counter + 1) != $counter)
         {
           echo(
"<br>was called by:<br>");
         }
       }
       exit();
   }
?>
bernyregeling AT hotmail DOT com
08-Aug-2003 07:29
I wrote this function, in addition to jlim, for a nice NO-HTML output.

Thee result has similarities to a Java-error. Hope you like it.

(BTW, this function exits the script too, if debug_backtrace is displayed)
------------------------------
   function debug_bt()
   {
       if(!function_exists('debug_backtrace'))
       {
           echo 'function debug_backtrace does not exists'."\r\n";
           return;
       }
       //echo '<pre>';
       echo "\r\n".'----------------'."\r\n";
       echo 'Debug backtrace:'."\r\n";
       echo '----------------'."\r\n";
       foreach(debug_backtrace() as $t)
       {
           echo "\t" . '@ ';
           if(isset($t['file'])) echo basename($t['file']) . ':' . $t['line'];
           else
           {
               // if file was not set, I assumed the functioncall
               // was from PHP compiled source (ie XML-callbacks).
               echo '<PHP inner-code>';
           }

           echo ' -- ';

           if(isset($t['class'])) echo $t['class'] . $t['type'];

           echo $t['function'];

           if(isset($t['args']) && sizeof($t['args']) > 0) echo '(...)';
           else echo '()';

           echo "\r\n";
       }
       //echo '</pre>';
       exit;
         }
jlim#natsoft.com.my
13-Mar-2003 09:51
Pretty print the backtrace(). Functions are indented based on call value, and file is linked using file:// for convenience.

Enjoy, John Lim

   function adodb_backtrace($print=true)
   {
       $s = '';
       if (PHPVERSION() >= 4.3) {
      
           $MAXSTRLEN = 64;
      
           $s = '<pre align=left>';
           $traceArr = debug_backtrace();
           array_shift($traceArr);
           $tabs = sizeof($traceArr)-1;
           foreach ($traceArr as $arr) {
               for ($i=0; $i < $tabs; $i++) $s .= ' &nbsp; ';
               $tabs -= 1;
               $s .= '<font face="Courier New,Courier">';
               if (isset($arr['class'])) $s .= $arr['class'].'.';
               foreach($arr['args'] as $v) {
                   if (is_null($v)) $args[] = 'null';
                   else if (is_array($v)) $args[] = 'Array['.sizeof($v).']';
                   else if (is_object($v)) $args[] = 'Object:'.get_class($v);
                   else if (is_bool($v)) $args[] = $v ? 'true' : 'false';
                   else {
                       $v = (string) @$v;
                       $str = htmlspecialchars(substr($v,0,$MAXSTRLEN));
                       if (strlen($v) > $MAXSTRLEN) $str .= '...';
                       $args[] = $str;
                   }
               }
              
               $s .= $arr['function'].'('.implode(', ',$args).')';
               $s .= sprintf("</font><font color=#808080 size=-1> # line %4d,".
  " file: <a href=\"file:/%s\">%s</a></font>",
  $arr['line'],$arr['file'],$arr['file']);
               $s .= "\n";
           }   
           $s .= '</pre>';
           if ($print) print $s;
       }
       return $s;
   }