文字

debug_backtrace

(PHP 4 >= 4.3.0, PHP 5, PHP 7)

debug_backtrace产生一条回溯跟踪(backtrace)

说明

array debug_backtrace ([ int $options = DEBUG_BACKTRACE_PROVIDE_OBJECT [, int $limit = 0 ]] )

debug_backtrace() 产生一条 PHP 的回溯跟踪(backtrace)。

参数

options

截至 5.3.6,这个参数是以下选项的位掩码:

debug_backtrace() 选项
DEBUG_BACKTRACE_PROVIDE_OBJECT 是否填充 "object" 的索引。
DEBUG_BACKTRACE_IGNORE_ARGS 是否忽略 "args" 的索引,包括所有的 function/method 的参数,能够节省内存开销。
在 5.3.6 之前,仅仅能使用的值是 TRUE 或者 FALSE ,分别等于是否设置 DEBUG_BACKTRACE_PROVIDE_OBJECT 选项。
limit

截至 5.4.0,这个参数能够用于限制返回堆栈帧的数量。 默认为 (limit=0) ,返回所有的堆栈帧。

返回值

返回一个包含众多关联数组的 array 。 以为为有可能返回的元素:

有可能从 debug_backtrace() 返回的元素
名字 类型 说明
function string 当前的函数名,参见: __FUNCTION__。
line integer 当前的行号。参见: __LINE__。
file string 当前的文件名。参见: __FILE__。
class string 当前 class 的名称。参见 __CLASS__
object object 当前的 object。
type string 当前调用的类型。如果是一个方法,会返回 "->"。如果是一个静态方法,会返回 "::"。 如果是一个函数调用,则返回空。
args array 如果在一个函数里,这会列出函数的参数。 如果是在一个被包含的文件里,会列出包含的文件名。

更新日志

版本 说明
5.4.0 添加了可选的参数 limit
5.3.6 参数 provide_object 改成 options,并且增加了可选参数 DEBUG_BACKTRACE_IGNORE_ARGS
5.2.5 添加了可选参数 provide_object
5.1.1 添加了当前的 object 为可能返回的元素。

范例

Example #1 debug_backtrace() 范例

<?php
// filename: /tmp/a.php

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

a_test ( 'friend' );
?>

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

执行 /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"
  }
}

参见

  • trigger_error() - 产生一个用户级别的 error/warning/notice 信息
  • debug_print_backtrace() - 打印一条回溯。

用户评论:

[#1] anoam at yandex dot ru [2014-10-17 08:12:03]

It works a little bit different with resources in different PHP versions.

For example:
function foo($bar)
{
  return debug_backtrace();
}

$resource = fopen(__FILE__, 'r');
$backtrace = foo($resource);
echo "when resource is opened: " . gettype($backtrace[0]['args'][0]) . "\n";
fclose($resource);
echo "when resource is closed: " . gettype($backtrace[0]['args'][0]) . "\n";

With 5.3.10 I got:
when resource is opened: resource
when resource is closed: resource

With 5.5.9:
when resource is opened: resource
when resource is closed: unknown type

Be carefull.

[#2] jonas at faceways dot se [2013-09-20 07:41:11]

When using debug_backtrace() to check if you're being accessed from another caller, please remember to ask debug_backtrace to only go as far as needed in depth and skip taking the entire debug object as return parameter:

<?php
    
if (count(debug_backtrace(FALSE1)) == 0)
    {
        
// Do something
    
}
?>

[#3] jurchiks101 at gmail dot com [2013-05-21 10:04:54]

Here's a function I just wrote for getting a nice and comprehensible call trace. It is probably more resource-intensive than some other alternatives but it is short, understandable, and gives nice output (Exception->getTraceAsString()).

<?php
function generateCallTrace()
{
    
$e = new Exception();
    
$trace explode("\n"$e->getTraceAsString());
    
// reverse array to make steps line up chronologically
    
$trace array_reverse($trace);
    
array_shift($trace); // remove {main}
    
array_pop($trace); // remove call to this method
    
$length count($trace);
    
$result = array();
    
    for (
$i 0$i $length$i++)
    {
        
$result[] = ($i 1)  . ')' substr($trace[$i], strpos($trace[$i], ' ')); // replace '#someNum' with '$i)', set the right ordering
    
}
    
    return 
"\t" implode("\n\t"$result);
}
?>


Example output:
1) /var/www/test/test.php(15): SomeClass->__construct()
2) /var/www/test/SomeClass.class.php(36): SomeClass->callSomething()

[#4] Anonymous [2013-03-06 09:01:17]

A usual entry looks like this:
<?php
array(6) {
  
'file' =>
  
string(87"DbSelector.php"
  'line' 
=>
  
int(171)
  
'function' =>
  
string(5"error"
  'class' 
=>
  
string(42"LoggingService"
  'type' 
=>
  
string(2"::"
  'args' 
=>
  array(
1) {
    [
0] =>
    
string(27"Connecting to DB: unittests"
  
}
}
?>


Be warned though that 'file' and 'class' do not reference the same thing!
'file' means which file calls the next step.
'class' is the next step being called.

So 'file' is the caller, 'class' is the callee.

[#5] Gemorroj [2013-02-11 09:58:58]

Another variation formatting backtrace.
Parameter $ignore to ignore the extra calls.
<?php

protected function getBacktrace($ignore 2)
{
    
$trace '';
    foreach (
debug_backtrace() as $k => $v) {
        if (
$k $ignore) {
            continue;
        }

        
array_walk($v['args'], function (&$item$key) {
            
$item var_export($itemtrue);
        });

        
$trace .= '#' . ($k $ignore) . ' ' $v['file'] . '(' $v['line'] . '): ' . (isset($v['class']) ? $v['class'] . '->' '') . $v['function'] . '(' implode(', '$v['args']) . ')' "\n";
    }

    return 
$trace;
}
?>

[#6] nyoung55 at that_google_mail.com [2013-01-31 16:31:55]

Here is a function to cleanly output the debug_backtrace to the error_log

<?php

function log_trace($message '') {
    
$trace debug_backtrace();
    if (
$message) {
        
error_log($message);
    }
    
$caller array_shift($trace);
    
$function_name $caller['function'];
    
error_log(sprintf('%s: Called from %s:%s'$function_name$caller['file'], $caller['line']));
    foreach (
$trace as $entry_id => $entry) {
        
$entry['file'] = $entry['file'] ? : '-';
        
$entry['line'] = $entry['line'] ? : '-';
        if (empty(
$entry['class'])) {
            
error_log(sprintf('%s %3s. %s() %s:%s'$function_name$entry_id 1$entry['function'], $entry['file'], $entry['line']));
        } else {
            
error_log(sprintf('%s %3s. %s->%s() %s:%s'$function_name$entry_id 1$entry['class'], $entry['function'], $entry['file'], $entry['line']));
        }
    }
}
?>

[#7] Anonymous [2013-01-30 20:12:49]

Simple function to get a string in form "filename: [class->][function(): ]"

<?php
function get_caller_info() {
    
$c '';
    
$file '';
    
$func '';
    
$class '';
    
$trace debug_backtrace();
    if (isset(
$trace[2])) {
        
$file $trace[1]['file'];
        
$func $trace[2]['function'];
        if ((
substr($func07) == 'include') || (substr($func07) == 'require')) {
            
$func '';
        }
    } else if (isset(
$trace[1])) {
        
$file $trace[1]['file'];
        
$func '';
    }
    if (isset(
$trace[3]['class'])) {
        
$class $trace[3]['class'];
        
$func $trace[3]['function'];
        
$file $trace[2]['file'];
    } else if (isset(
$trace[2]['class'])) {
        
$class $trace[2]['class'];
        
$func $trace[2]['function'];
        
$file $trace[1]['file'];
    }
    if (
$file != ''$file basename($file);
    
$c $file ": ";
    
$c .= ($class != '') ? ":" $class "->" "";
    
$c .= ($func != '') ? $func "(): " "";
    return(
$c);
}
?>


Usage like:

<?php
function debug($str) {
    echo 
get_caller_info() . $str "<br>\n";
}
?>


get_caller_info() will return info about the function /class->method that called debug().

[#8] root at jackyyf dot com [2012-12-22 12:05:33]

When use register_shutdown_function, and the function called when shutting down, there are no line number nor filename information about this function, only function, class(if possible), type(if possible) and args are provided.

[#9] Phil Hilton [2012-11-16 18:57:33]

Super simple example to output where your function was called from (file, function, line number):

<?php
// Prints the file name, function name, and 
// line number which called your function
// (not this function, then one that  called 
// it to begin with) 
function debugPrintCallingFunction () {
    
$file 'n/a';
    
$func 'n/a'
    
$line 'n/a';
    
$debugTrace debug_backtrace();
    if (isset(
$debugTrace[1])) {
        
$file $debugTrace[1]['file'] ? $debugTrace[1]['file'] : 'n/a';
        
$line $debugTrace[1]['line'] ? $debugTrace[1]['line'] : 'n/a';
    }
    if (isset(
$debugTrace[2])) $func $debugTrace[2]['function'] ? $debugTrace[2]['function'] : 'n/a';
    echo 
"<pre>\n$file$func$line\n</pre>";
}
?>

[#10] d at rren dot me [2012-10-04 07:35:34]

Howdy guys, just a note really - The ['args'] data within the resulting array is supplied by reference. I found myself editing the reference unknowingly which in turn shows its ugly head further down the line if you call multiple backtrace.

<?php
$trace 
array_reverse(debug_backtrace());

// LOOP BACKTRACE
$la 0;
$lb count($trace);
while (
$la<$lb){

    
// DATA FROM BACKTRACE
    
$trace[$la]['file'];
    
$trace[$la]['line'];
    
$trace[$la]['args'];
    
$trace[$la]['function'];
    
// DATA FROM BACKTRACE

    // LOOP ARGUMENTS ARRAY
    
$ba 0;
    
$bb count($trace[$la]['args']);
    while (
$ba<$bb){

        
$trace[$la]['args'][$ba] = "EDITING A REFERENCE/POINTER";

        
$ba++;
    }
    unset(
$bb);
    unset(
$ba);
    
// LOOP ARGUMENTS ARRAY

    
$la++;
}
unset(
$lb);
unset(
$la);
// LOOP BACKTRACE
?>

[#11] kexianbin at diyism dot com [2012-09-16 02:26:07]

need no Xdebug or dbg.so on server, return more detailed message:

diyism_trace.php:
<?php
define
(TRACES_MODE'TEXTAREA');//'TEXTAREA' or 'FIREPHP'
$GLOBALS['traces.pre']=array();
function 
my_array_diff($arr1$arr2)
         {foreach (
$arr1 as $k=>$v)
                  {if (
in_array($v$arr2true))
                      {unset(
$arr1[$k]);
                      }
                  }
          return 
$arr1;
         }
function 
my_var_export($var$is_str=false)
         {
$rtn=preg_replace(array('/Array\s+\(/''/\[(\d+)\] => (.*)\n/''/\[([^\d].*)\] => (.*)\n/'), array('array (''\1 => \'\2\''."\n"'\'\1\' => \'\2\''."\n"), substr(print_r($vartrue), 0, -1));
          
$rtn=strtr($rtn, array("=> 'array ('"=>'=> array ('));
          
$rtn=strtr($rtn, array(")\n\n"=>")\n"));
          
$rtn=strtr($rtn, array("'\n"=>"',\n"")\n"=>"),\n"));
          
$rtn=preg_replace(array('/\n +/e'), array('strtr(\'\0\', array(\'    \'=>\'  \'))'), $rtn);
          
$rtn=strtr($rtn, array(" Object',"=>" Object'<-"));
          if (
$is_str)
             {return 
$rtn;
             }
          else
              {echo 
$rtn;
              }
         }
function 
tick_handler()
         {
$tmp=debug_backtrace();
          
$trace=my_array_diff($tmp$GLOBALS['traces.pre']);
          
//echo '<pre>';var_export($trace);echo '</pre>';echo '<br/>'; //for debug diyism_trace.php
          
$trace=array_values($trace);
          
$GLOBALS['traces.pre']=$tmp;
          if (
count($trace)>&& $trace[0]['file'].'/'.@$tmp[1]['function']!==@$GLOBALS['traces'][count($GLOBALS['traces'])-1]['key']) //filter empty array and rearrange array_values(), because some lines will trigger two tick events per line, for example: 1.last line is "some code;questmark>" 2.error_reporting(...
             
{for ($i=count($trace)-1$i>=0; --$i)
                  {
$GLOBALS['traces'][]=$tmp_fb=array_merge(array('key'=>$trace[$i]['file'].'/'.@$tmp[$i+1]['function']), $trace[$i], array('function'=>strtr($trace[$i]['function'], array('tick_handler'=>'CONTINUE')), 'in_function'=>@$tmp[$i+1]['function']));
                   
TRACES_MODE==='FIREPHP'?fb(trace_output($tmp_fb), 'diyism_trace:'.++$GLOBALS['diyism_trace_no']):'';
                  }
             }
         }
function 
trace_output($trace)
         {
$trace['in_function']=strtr(@$trace['in_function'], array('require'=>'''require_once'=>'''include'=>'''include_once'=>''));
          
$trace['args']=$trace['args']?strtr(preg_replace(array('/\n +/'), array(''), preg_replace(array('/\n  \d+ => /'), array(''), substr(my_var_export($trace['args'], true), 7, -3))), array("\r"=>'\r'"\n"=>'\n')):'';
          return 
$trace['file'].($trace['in_function']?'/'.$trace['in_function'].'()':'').'/'.$trace['line'].': '.$trace['function'].'('.$trace['args'].')';
         }
function 
traces_output()
         {echo 
'<textarea style="width:100%;height:300px;">';
          
$GLOBALS['traces']=array_slice($GLOBALS['traces'], 2);//remove registering tick line and requiring 'diyism_trace.php' line
          
foreach ($GLOBALS['traces'] as $k=>$trace)
                  {echo 
htmlentities($k.':'.trace_output($trace)."\n");
                  }
          echo 
'</textarea>';
         }
register_tick_function('tick_handler');
TRACES_MODE==='TEXTAREA'?register_shutdown_function('traces_output'):'';
?>


test.php:
<?php
declare(ticks=1);
require 
'diyism_trace.php';

a('a', array('hello'));
1+2;
b();
function 
a()
         {
$d=1;
          
b();
          
$d=2;
         }
function 
b()
         {
1+1;
         }
?>

[#12] ciprian dot stingu at gmail dot com [2011-11-19 12:32:35]

A function that i use for debug
I shortened variables name and i eliminated the spaces from second function in order fit in post :(

<?php
define
("LFP"'./lt.log');
function 
LogTrace($Argument$lfn LFP$itw '  ')
{
    
error_log("=====\r"3$lfn); 
    
error_log("[BEGIN BACKTRACE]\r"3$lfn); 
    
$it '';
    
$Ts array_reverse(debug_backtrace());
    foreach(
$Ts as $T)
       {  
        if(
$T['function'] != 'include' && $T['function'] != 'require' && $T['function'] != 'include_once' && $T['function'] != 'require_once')
        {
            
$ft $it '<'basename($T['file']) . '> on line ' $T['line'];  
            if(
$T['function'] != 'LogTrace')
            {
                if(isset(
$T['class']))
                    
$ft .= ' in method ' $T['class'] . $T['type'];
                else 
                    
$ft .= ' in function ';
                
$ft .= $Trace['function'] . '(';
            }
            else
                
$ft .= '(';
            if(isset(
$T['args'][0]))
            {
                if(
$T['function'] != 'LogTrace')
                {
                    
$ct '';
                    foreach(
$T['args'] as $A)
                    {
                        
$ft .= $ct LogVar($A''$it$itw0);
                        
$ct $it $itw ',';
                    }
                }
                else
                    
$ft .= LogVar($T['args'][0], ''$it$itw0);
            }
            
$ft .= $it ")\r";
            
error_log($ft3$lfn); 
            
$it .= $itw;
        }            
    }
    
error_log("[END BACKTRACE]\r"3$lfn);
}

function 
LogVar(&$Var$vn$pit$itw$nlvl$m '')
{
    if(
$nlvl>=16) return;
    if(
$nlvl==0){$tv=serialize($Var);$tv=unserialize($tv);}
    else 
$tv=&$Var
    
$it=$pit.$itw;
    for(
$i=0$i<$nlvl;$i++) $it.='.'.$itw;
    
$o='';$nl="\n";
    if(
is_array($tv))
    {
        if(
strlen($vn)>0$o.=$it.$m.'<array> $'.$vn.' = (';
        else 
$o.="\r".$it.$m.'<array> = (';
        
$o.= $nl;$AK=array_keys($tv);
        foreach(
$AK as $AN) {$AV=&$tv[$AN];$o.=LogVar($AV,$AN,$pit,$itw,$nlvl+1);}
        
$o.=$it.')'.$nl;
    }
    else if(
is_string($tv))
    {
        if(
strlen($vn)>0)$o.=$it.$m.'<string> $'.$vn.' = ';
        else 
$o.=' '.$m.'<string> = ';
        if(
$tv===null$o.='NULL';
        else 
$o.='"'.$tv.'"';
        
$o.=$nl;
    }
    else if(
is_bool($tv))
    {
        if(
strlen($vn) > 0$o.=$it.$m.'<boolean> $'.$vn.' = ';
        else 
$o.=' '.$m.'<boolean> = ';
        if(
$tv===true$o.='TRUE';
        else 
$o.='FALSE';
        
$o.=$nl;
    }
    else if(
is_object($tv))
    {
        if(
strlen($vn)>0)
        {
            
$o.=$pit.$itw;
            for(
$i=0;$i<$nlvl;$i++) $o.='.'.$itw;
            
$o.=$m.'<'.get_class($tv).'::$'.$vn.'> = {'.$nl;
        }
        else 
$o.=' '.$m.'<'.get_class($tv).'::> = {'.$nl;
        
$R=new ReflectionClass($tv);
        
$o.=$it.'.'.$itw.'Class methods {'.$nl;
        
$CM=$R->getMethods();
        foreach(
$CM as $MN => $MV)
        {
            
$o.=$it.'.'.$itw.'.'.$itw.implode(' ',Reflection::getModifierNames($MV->getModifiers())).' '.$MV->getName().'(';
            
$MP=$MV->getParameters(); $ct='';
            foreach(
$MP as $MPN => $MPV)
            {
                
$o.=$ct$o.=$MPV->isOptional()?'[':'';
                if(
$MPV->isArray()) $o.='<array> ';
                else if(
$MPV->getClass()!==null$o.='<'.$MPV->getClass()->getName().'::> ';
                
$o.=$MPV->isPassedByReference()?'&':''$o.='$'.$MPV->getName();
                if(
$MPV->isDefaultValueAvailable())
                 {
                    if(
$MPV->getDefaultValue()===null$o.=' = NULL';
                    else if(
$MPV->getDefaultValue()===true$o.=' = TRUE';
                    else if(
$MPV->getDefaultValue()===false$o.=' = FALSE';    
                    else 
$o.=' = '.$MPV->getDefaultValue();    
                }
                
$o.=$MPV->isOptional()?']':''$ct=', ';
            }
            
$o.=')'.$nl;
        }
        
$o.=$it.'.'.$itw.'}'.$nl$o.=$it.'.'.$itw.'Class properties {'.$nl;
        
$CV=$R->getProperties();
        foreach(
$CV as $CN => $CV)
        {
            
$M=implode(' ',Reflection::getModifierNames($CV->getModifiers())).' ';
            
$CV->setAccessible(true); 
            
$o.=LogVar($CV->getValue($tv),$CV->getName(),$pit,$itw,$nlvl+2,$M);
        }
        
$o.=$it.'.'.$itw.'}'.$nl$o.=$it.'.'.$itw.'Object variables {'.$nl;
         
$OVs=get_object_vars($tv);    
        foreach(
$OVs as $ON => $OV$o.=LogVar($OV,$ON,$pit,$itw,$nlvl+2);
        
$o.=$it.'.'.$itw.'}'.$nl$o.=$pit.$itw;
        for(
$i=0;$i<$nlvl;$i++)    $o.='.'.$itw;
        
$o.='}'.$nl;
    }
    else
    {
        if(
strlen($vn)>0$o.=$it.$m.'<'.gettype($tv).'> $'.$vn.' = '.$tv;
        else 
$o.=' '.$m.'<'.gettype($tv).'> = '.$tv;
        
$o.=$nl;
    }          
    return 
$o;    
}
//test
date_default_timezone_set('Europe/Bucharest');
$date = new DateTime('2010-01-28');
LogTrace($date); 
?>

[#13] Bill Getas [2010-12-21 03:09:45]

Here's my little updated contribution - it prints colorful output in the way I prefer.  Define a helper function isRootIp() that contains an array including your IP; then calls to bt() simply return, so you can sprinkle backtraces in live sites w/o anyone knowing.

<?php
function bt()
{
    if( ! 
isRootIp() )
    {
        return 
false;
    }
    
array_walkdebug_backtrace(), create_function'$a,$b''print "<br /><b>". basename( $a[\'file\'] ). "</b> &nbsp; <font color=\"red\">{$a[\'line\']}</font> &nbsp; <font color=\"green\">{$a[\'function\']} ()</font> &nbsp; -- ". dirname( $a[\'file\'] ). "/";' ) );
}
?>

[#14] henzeberkheij at gmail dot com [2010-10-10 02:07:48]

I find it useful to know if a function is being called. in Java for instance you usually print a line with the functionname and arguments in the beginning of the function. I wanted to achieve the same thing in php thus i wrote the following class:

<?php
class Debug 
{
    private static 
$calls;

    public static function 
log($message null)
    {
        if(!
is_array(self::$calls))
            
self::$calls = array();

        
$call debug_backtrace(false);
        
$call = (isset($call[1]))?$call[1]:$call[0];

        
$call['message'] = $message;
        
array_push(self::$calls$call);
    }
}
?>


include this class before anything else
usage: Debug::log($message); at the beginning of your function.

write yourself a nice printout of the data;

[#15] kenorb at gmail dot com [2010-09-07 07:11:46]

One line of code to print simplest and shortest human readable backtrace:)
<?php
array_walk
(debug_backtrace(),create_function('$a,$b','print "{$a[\'function\']}()(".basename($a[\'file\']).":{$a[\'line\']}); ";'));
?>

[#16] php noob [2010-09-02 20:32:48]

Surprisingly, no one has described one of the best uses of this: dumping a variable and showing the location. When debugging, especially a big and unfamiliar system, it's a pain remembering where I added those var dumps. Also, this way there is a separator between multiple dump calls.

<?php

function dump$var ) {
    
$result var_export$vartrue );
    
$loc whereCalled();
    return 
"\n<pre>Dump: $loc\n$result</pre>";
}

function 
whereCalled$level ) {
    
$trace debug_backtrace();
    
$file   $trace[$level]['file'];
    
$line   $trace[$level]['line'];
    
$object $trace[$level]['object'];
    if (
is_object($object)) { $object get_class($object); }

    return 
"Where called: line $line of $object \n(in $file)";
}
?>


In addition, calling 'whereCalled()' from any function will quickly identify locations that are doing something unexpected (e.g., updating a property at the wrong time). I'm new to PHP, but have used the equivalent in Perl for years.

[#17] jlammertink at gmail dot com [2010-07-15 02:32:27]

I use this simple but effective function so i can see which method in the child class called the current method (in the parent class).

<?php
function get_caller_method()
{
    
$traces debug_backtrace();

    if (isset(
$traces[2]))
    {
        return 
$traces[2]['function'];
    }

    return 
null;
}
?>

[#18] john dot risken at gmail dot com [2010-02-25 22:02:15]

Everybody seems to have their favorite use.  I substitute this function for die().  It gives a message 
to the user and emails me a PrettyPrint of what went wrong.  $info is set by me, 
and it does a special check in the database object.

<?php
// var_format

function var_format($v// pretty-print var_export
{
    return (
str_replace(array("\n"," ","array"),
array(
"<br>","&nbsp;","&nbsp;<i>array</i>"),
var_export($v,true))."<br>");
}
function 
myDie($info
{
    
$mysqlerr=strpos($info,"ERROR=You have an error in your SQL syntax");
    if(
$mysqlerr>0)$info=substr($info,0,$mysqlerr)." mySql format error";
    
$out="<br>MSG='$info'<br>".var_format($_REQUEST)."<br>";
    
$bt=debug_backtrace();
    
$sp=0;
    
$trace="";
    foreach(
$bt as $k=>$v)
    {
        
extract($v);
        
$file=substr($file,1+strrpos($file,"/"));
        if(
$file=="db.php")continue; // the db object
        
$trace.=str_repeat("&nbsp;",++$sp); //spaces(++$sp);
        
$trace.="file=$file, line=$line, function=$function<br>";        
    } 
    
$out.="<br>".backTrace();
    if(
substr($info,0,4)=="XXX "// special errrors when db is inaccessible
    
{
        
$out=str_replace("<br>","\n",$out);
        
$out=str_replace("&nbsp;"," ",$out);
        
mail("me@example.com","Database Execution Error for user ".$REMOTE_ADDR,"$out");
        exit(
"Database Access Error. Please try again later.");
    }
    
mail("me@example.com",'Error Monitor','Execution Error',$out);
    exit(
"DANG! An execution error in the program has been sent to the webmaster. 
If you don't get an email from him soon, please call him."
);
}
?>


This produces an output like this

 file=badmode.php, line=5, function=backTrace
  file=login.php, line=209, function=require
   file=midScreen.php, line=264, function=require
    file=masterindex.php, line=161, function=require
     file=production2.php, line=121, function=require
      file=index.php, line=16, function=require

[#19] michael dot schramm at gmail dot com [2009-10-20 00:29:02]

Be carefull if you are using objects as arguments for function calls!

<?php
error_reporting
(E_ALL);

function 
myPrint($trace){
    foreach(
$trace as $i=>$call){
        

        
if (is_object($call['object'])) { $call['object'] = 'CONVERTED OBJECT OF CLASS '.get_class($call['object']); }
        if (
is_array($call['args'])) {
            foreach (
$call['args'] AS &$arg) {
                if (
is_object($arg)) { $arg 'CONVERTED OBJECT OF CLASS '.get_class($arg); }
            }
        }
        
        
$trace_text[$i] = "#".$i." ".$call['file'].'('.$call['line'].') ';
        
$trace_text[$i].= (!empty($call['object'])?$call['object'].$call['type']:'');
        
$trace_text[$i].= $call['function'].'('.implode(', ',$call['args']).')';
    }
    
    
var_dump($trace_text);
}

class 
A{
    public function 
test($obj){
        
$obj->test();
    }
}

class 
B{
    public function 
test(){
        echo 
myPrint(debug_backtrace());
    }
}

$A = new A();
$B = new B();

$A->test($B);

?>

[#20] frank at frank dot com [2008-05-07 11:12:27]

Here is my simple example:
Code printing variable of class which instatiates the printing class.

Well, I am sure you understand when looking at the code:
Print result is: jippii

<?php
class {

        function 
something() {
                
$s debug_backtrace();
                
                
$callingObject $s[1]['object']; 
                
$test $callingObject->jip;
                print 
$test;
        }

}

class 
{
      var 
$jip
      
        function 
execute() {
                
$a = new A();
                
$this->jip "jippii";  
                
$a->something(); 
        }

}
$control = new B();
$control->execute();
?>

[#21] samthor [2008-02-11 00:04:05]

Here's a way to get the arguments for an upstream function in your stack (works with class methods, static methods and non-class methods):
<?php

function getArgs$target$subclass_ok true ) {

    if( 
strpos$target"::" ) ) {
        list( 
$class$target ) = explode"::"$target);
        
$type "::";
    }
    else if( 
strpos$target"->" ) ) {
        list( 
$class$target ) = explode"->"$target);
        
$type "->";
    }
    else {
        
$type NULL;
        
$class NULL;
    }
    
$class and $class = new ReflectionClass$class );

    foreach( 
debug_backtrace() as $obj ) {

        if( 
$obj['function'] == $target ) {
            if( 
$type and $obj['type'] == $type ) {
                
$_cl = new ReflectionClass$obj['class'] );
                if( 
$_cl->getName() == $class->getName() or ( $subclass_ok and $_cl->isSubclassOf$class ) ) ) {
                    return 
$obj['args'];
                }
                unset( 
$_cl );
            }
            else if( !
$type ) {
                return 
$obj['args'];
            }
        }

    }

    return 
NULL;

}
?>


Some example usage:
<?php
class Foo {
    function 
test() {
        
$args getArgs"Foo->base" );
        print( 
"the parameter 'v' to my call of base was: {$args[0]}\n" );
    }
    function 
base$v ) {
        
$this->test();
    }
}

$f = new Foo();
$f->base713 ); // will print.. ".. my call of base was: 713"

?>


Trust me, there are some reasons for why you might want to do this :)

[#22] aryel at iku dot com dot br [2008-01-29 14:40:51]

An easy function to pull all details of the debug backtrace:

<?php
function getDebugBacktrace($NL "<BR>") {
    
$dbgTrace debug_backtrace();
    
$dbgMsg .= $NL."Debug backtrace begin:$NL";
    foreach(
$dbgTrace as $dbgIndex => $dbgInfo) {
        
$dbgMsg .= "\t at $dbgIndex  ".$dbgInfo['file']." (line {$dbgInfo['line']}) -> {$dbgInfo['function']}(".join(",",$dbgInfo['args'])")$NL";
    }
    
$dbgMsg .= "Debug backtrace end".$NL;
    return 
$dbgMsg;
}
?>


Then you can call it anywhere you want to get a string with the debug backtrace in readable format (i.e. your error handling function)

<?php
$backtrace 
getDebugBacktrace();
echo 
"Fatal error! Cannot connect to database!";
echo 
$backtrace;
?>


If you're running on command line, you might want to replace the line split. You can do that thru the function argument:

<?php
$backtrace 
getDebugBacktrace("\n");
echo 
"Error! Server is running out of foos! Dumping error backtrace";
echo 
$backtrace;
?>


Hope that helps,
Aryel

[#23] php at kennel17 dot co dot uk [2007-06-20 09:30:08]

Further to my previous note, the 'object' element of the array can be used to get the parent object.  So changing the get_class_static() function to the following will make the code behave as expected:

<?php
    
function get_class_static() {
        
$bt debug_backtrace();
    
        if (isset(
$bt[1]['object']))
            return 
get_class($bt[1]['object']);
        else
            return 
$bt[1]['class'];
    }
?>


HOWEVER, it still fails when being called statically.  Changing the last two lines of my previous example to

<?php
  foo
::printClassName();
  
bar::printClassName();
?>


...still gives the same problematic result in PHP5, but in this case the 'object' property is not set, so that technique is unavailable.

[#24] php at kennel17 dot co dot uk [2007-06-20 09:01:02]

The value of the class argument has changed slightly between PHP4 and PHP5:

Here's an example:

<?php

  
function get_class_static() {
    
$bt debug_backtrace();
    
$name $bt[1]['class'];
    return 
$name;
  }

  class 
foo {
    function 
printClassName() {
      print(
get_class_static() . "\n");
     }
  }

  class 
bar extends foo {
  }

$f = new foo();
$b = new bar();
$f->printClassName();
$b->printClassName();

?>


In PHP4 you get:

  foo
  bar

In PHP5 you get:

  foo
  foo

debug_backtrace() now sets the 'class' parameter to be the class that the function is actually defined in, not the name of the instantiated class.

[#25] jsnell at e-normous dot com [2007-05-30 14:35:46]

If you are using the backtrace function in an error handler, avoid using var_export() on the args, as you will cause fatal errors in some situations, preventing you from seeing your stack trace.  Some structures will cause PHP to generate the fatal error "Nesting level too deep - recursive dependency?" This is a design feature of php, not a bug (see http://bugs.php.net/bug.php?id=30471)

[#26] kroczu AT interia DOT pl [2007-01-23 10:24:35]

<?php
// useful and comfortable debug function
// it's show memory usage and time flow between calls, so we can quickly find a block of code that need optimisation...
// example result:


function debug()
{
   static 
$start_time NULL;
   static 
$start_code_line 0;

   
$call_info array_shiftdebug_backtrace() );
   
$code_line $call_info['line'];
   
$file array_popexplode('/'$call_info['file']));

   if( 
$start_time === NULL )
   {
       print 
"debug ".$file."> initialize\n";
       
$start_time time() + microtime();
       
$start_code_line $code_line;
       return 
0;
   }

   
printf("debug %s> code-lines: %d-%d time: %.4f mem: %d KB\n"$file$start_code_line$code_line, (time() + microtime() - $start_time), ceilmemory_get_usage()/1024));
   
$start_time time() + microtime();
   
$start_code_line $code_line;
}

////////////////////////////////////////////////
// example:

debug();
sleep(2);
debug();
// soft-code...
$a 5;
debug();

// hard-code
for( $i=0$i<100000$i++)
{
    
$dummy['alamakota'.$i] = 'alamakota'.$i;
}
debug();
usleep(100000);
debug();
unset(
$dummy);
debug();

?>

[#27] seaside dot ki at mac dot com [2006-12-14 16:20:34]

I've started creating an external debug server for PHP. A PHP app require_once's a TADebugger(), which communicates with the debug sever. Find the OS X universal binary here [PHP source sample included]:

   http://www.turingart.com/downloads/phpDebugger.zip

Currently, TADebugger allows to post these properties back to the debug server:

- Call backtraces
- String messages
- Source files, which were referenced by a backtrace call

Note, that the binary is a early version.

[#28] icefragment at gmail dot com [2006-09-23 09:34:18]

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 />");
}
}

[#29] zmorris at mac dot com [2006-09-20 19:48:06]

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$vartrue ) );    // 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_reversedebug_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()' );
}

test1.1"param2\n", array( => "a\n""b\n" => ), false );

?>

[#30] admin at sgssweb dot com [2006-08-13 02:30:06]

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"));

?>

[#31] tiwen at rpgame dot de [2006-04-30 13:25:45]

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!");
?>

[#32] http://synergy8.com [2005-12-13 22:37:40]

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
}

?>

[#33] tb [2005-07-21 11:18:46]

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 {
    
    

    
abstract function debug($msg);
    
    

    
abstract function error($msg);
    
    

    
abstract function warning($msg);
    
    

    
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

[#34] diz at ysagoon dot com [2004-11-24 02:35:18]

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.

[#35] diz at ysagoon dot com [2004-11-23 14:40:56]

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($a064)).((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)

[#36] ad-rotator.com [2004-04-30 09:11:14]

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

[#37] spagmoid at yahoo dot NOSPAMcom [2003-12-09 11:47:36]

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

[#38] Fabian dot Kraetzer at gmx dot de [2003-09-01 06:18:08]

I coded a function, too. Just call debug() evertime you think you could encounter an error:
<?php
    
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"> <?php
              
echo($debug_array[$tmp_counter]["function"]);?>
(</font> <font color="#2020F0"> <?php
              
//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:  <?php
                
echo($debug_array[$tmp_counter]["file"]);?>
</font><br>
                <font color="#FFFFFF">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;line:  <?php
                
echo($debug_array[$tmp_counter]["line"]);?>
</font><br>
                <font color="#FFFFFF">}</font></td>
            </tr>
          </table>
           <?php
         
if(($tmp_counter 1) != $counter)
         {
           echo(
"<br>was called by:<br>");
         }
       }
        exit();
    }
?>

[#39] bernyregeling AT hotmail DOT com [2003-08-08 04:29:01]

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

[#40] jlim#natsoft.com.my [2003-03-13 05:51:25]

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

上一篇: 下一篇: