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