Error stack trace php

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

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

debug_backtraceGenerates a backtrace

Description

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

Parameters

options

This parameter is a bitmask for the following options:

debug_backtrace() options

DEBUG_BACKTRACE_PROVIDE_OBJECT Whether or not to populate the «object» index.
DEBUG_BACKTRACE_IGNORE_ARGS Whether or not to omit the «args» index, and thus all the function/method arguments,
to save memory.
limit

This parameter can be used to limit the number of stack frames returned.
By default (limit=0) it returns all stack frames.

Return Values

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

Possible returned elements from debug_backtrace()

Name Type Description
function string The current function name. See also
__FUNCTION__.
line int The current line number. See also
__LINE__.
file string The current file name. See also
__FILE__.
class string The current class name. See also
__CLASS__
object object The current object.
type string The current call type. If a method call, «->» is returned. If a static
method call, «::» is returned. If a function call, nothing is returned.
args array If inside a function, this lists the functions arguments. If
inside an included file, this lists the included file name(s).

Examples

Example #1 debug_backtrace() example


<?php
// filename: /tmp/a.phpfunction a_test($str)
{
echo
"nHi: $str";
var_dump(debug_backtrace());
}
a_test('friend');
?>

<?php
// filename: /tmp/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"
  }
}

See Also

  • trigger_error() — Generates a user-level error/warning/notice message
  • debug_print_backtrace() — Prints a backtrace

jurchiks101 at gmail dot com

9 years ago


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("nt", $result);
}
?>

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


Anonymous

10 years ago


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($func, 0, 7) == 'include') || (substr($func, 0, 7) == '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().


jsnell at e-normous dot com

15 years ago


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)

robert at medianis dot net

6 years ago


Just a short note on debug_backtrace options for PHP 5.3.6 or newer:

debug_backtrace() - show all options
debug_backtrace(0) - exlude ["object"]
debug_backtrace(1) - same as debug_backtrace()
debug_backtrace(2) - exlude ["object"] AND ["args"]

use this example and try calling debug_backtrace with different options

<?php
function F1()
{
    echo
"<br />";
    echo
"in F1 now";
    echo
"<pre>".print_r(debug_backtrace(2),true)."</pre>";
}

class

DebugOptionsTest
{
    function
F2()
    {
        echo
"<br />";
        echo
"in F2 now";
       
F1();
    }

}

echo

"<hr />calling F1";
F1();$c=new DebugOptionsTest();
echo
"<hr /><hr /><hr />calling F2";
$c->F2("testValue");?>


jake at qzdesign dot co dot uk

3 years ago


The `args` element contains only the arguments actually passed to the function or method.  It does not include default parameters if they were not explicitly specified.  (A least, this is the case with PHP 7.1.9.)  This is consistent with the behaviour of `func_get_args()`.

d at rren dot me

10 years ago


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

?>


michael dot schramm at gmail dot com

13 years ago


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){
       
/**
         * THIS IS NEEDED! If all your objects have a __toString function it's not needed!
         *
         * Catchable fatal error: Object of class B could not be converted to string
         * Catchable fatal error: Object of class A could not be converted to string
         * Catchable fatal error: Object of class B could not be converted to string
         */
       
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);?>


Emmett Brosnan

6 years ago


Quick and dirty formatted output from debug_backtrace.

$file_paths = debug_backtrace();

  foreach($file_paths AS $file_path) {
  foreach($file_path AS $key => $var) {
    if($key == 'args') {
      foreach($var AS $key_arg => $var_arg) {
        echo $key_arg . ': ' . $var_arg . '<br>';
      }
    } else {
      echo $key . ': ' . $var . '<br>';
    } 
  }
}


root at jackyyf dot com

10 years ago


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.

jcmargentina at gmail dot com

3 years ago


I want to point out that debug_backtrace() in new versions of php can detect recursion // circular references .. avoiding memory consumption.

Example:

<?phpclass ParentClass {
        public function
__construct()
        {
               
$this->_child = new ChildClass($this);
               
var_dump(debug_backtrace());
        }
}

class

ChildClass {
        public function
__construct(ParentClass $p)
        {
               
$this->_parent = $p;
        }
}
$test = new ParentClass();
?>

Output:

array(1) {
  [0]=>
  array(7) {
    ["file"]=>
    string(23) "/home/jcm/testdebug.php"
    ["line"]=>
    int(18)
    ["function"]=>
    string(11) "__construct"
    ["class"]=>
    string(11) "ParentClass"
    ["object"]=>
    object(ParentClass)#1 (1) {
      ["_child"]=>
      object(ChildClass)#2 (1) {
        ["_parent"]=>
        *RECURSION*
      }
    }
    ["type"]=>
    string(2) "->"
    ["args"]=>
    array(0) {
    }
  }
}

Attention in the *RECURSION* hint provided


kenorb at gmail dot com

12 years ago


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']}); ";'));
?>

jonas at faceways dot se

9 years ago


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(FALSE, 1)) == 0)
    {
       
// Do something
   
}
?>


anoam at yandex dot ru

8 years ago


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.


Bill Getas

12 years ago


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_walk( debug_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'] ). "/";' ) );

}

?>


jlammertink at gmail dot com

12 years ago


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;

}

?>


kroczu AT interia DOT pl

16 years ago


<?
// 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:
/*
debug example.php> initialize
debug example.php> code-lines: 39-41 time: 2.0002 mem: 19 KB
debug example.php> code-lines: 41-44 time: 0.0000 mem: 19 KB
debug example.php> code-lines: 44-51 time: 0.6343 mem: 9117 KB
debug example.php> code-lines: 51-53 time: 0.1003 mem: 9117 KB
debug example.php> code-lines: 53-55 time: 0.0595 mem: 49 KB
*/

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

   $call_info = array_shift( debug_backtrace() );
   $code_line = $call_info['line'];
   $file = array_pop( explode('/', $call_info['file']));

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

   printf("debug %s> code-lines: %d-%d time: %.4f mem: %d KBn", $file, $start_code_line, $code_line, (time() + microtime() - $start_time), ceil( memory_get_usage()/1024));
   $start_time = time() + microtime();
   $start_code_line = $code_line;
}

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

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

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

?>


nyoung55 at that_google_mail.com

10 years ago


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

<?php

/*

* Send the output from a backtrace to the error_log

* @param string $message Optional message that will be sent the the error_log before the backtrace

*/

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']));

        }

    }

}

?>


Anonymous

9 years ago


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.


Gemorroj

9 years ago


Another variation formatting backtrace.

Parameter $ignore to ignore the extra calls.

<?php

/**

* Getting backtrace

*

* @param int $ignore ignore calls

*

* @return string

*/

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($item, true);

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

    }

    return

$trace;

}

?>

kexianbin at diyism dot com

10 years ago


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, $arr2, true))
                      {unset(
$arr1[$k]);
                      }
                  }
          return
$arr1;
         }
function
my_var_export($var, $is_str=false)
         {
$rtn=preg_replace(array('/Arrays+(/', '/[(d+)] => (.*)n/', '/[([^d].*)] => (.*)n/'), array('array (', '1 => '2''."n", ''1' => '2''."n"), substr(print_r($var, true), 0, -1));
         
$rtn=strtr($rtn, array("=> 'array ('"=>'=> array ('));
         
$rtn=strtr($rtn, array(")nn"=>")n"));
         
$rtn=strtr($rtn, array("'n"=>"',n", ")n"=>"),n"));
         
$rtn=preg_replace(array('/n +/e'), array('strtr('', 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)>0 && $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;
         }
?>


php noob

12 years ago


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.

<?phpfunction dump( $var ) {
   
$result = var_export( $var, true );
   
$loc = whereCalled();
    return
"n<pre>Dump: $locn$result</pre>";
}

function

whereCalled( $level = 1 ) {
   
$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.


php at kennel17 dot co dot uk

15 years ago


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.


henzeberkheij at gmail dot com

12 years ago


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;


john dot risken at gmail dot com

12 years ago


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


http://synergy8.com

17 years ago


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


frank at frank dot com

14 years ago


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 A {

        function

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

}

class

B {
      var
$jip;

              function

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

}

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


samthor

14 years ago


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
/**
* getArgs - find arguments of upstream method
* can be called with, e.g. "funcname", "class::staticmethod", "class->instancemethod".
*/
function getArgs( $target, $subclass_ok = true ) {

    if(

strpos( $target, "::" ) ) {
        list(
$class, $target ) = explode( "::", $target, 2 );
       
$type = "::";
    }
    else if(
strpos( $target, "->" ) ) {
        list(
$class, $target ) = explode( "->", $target, 2 );
       
$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->base( 713 ); // will print.. ".. my call of base was: 713"?>

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

bernyregeling AT hotmail DOT com

19 years ago


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'."rn";

            return;

        }

        //echo '<pre>';

        echo "rn".'----------------'."rn";

        echo 'Debug backtrace:'."rn";

        echo '----------------'."rn";

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

        }

        //echo '</pre>';

        exit;

         }


seaside dot ki at mac dot com

16 years ago


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.


icefragment at gmail dot com

16 years ago


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

16 years ago


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.

<?phpfunction    print_var( $var )
{
   if(
is_string( $var ) )
       return(
'"'.str_replace( array("x00", "x0a", "x0d", "x1a", "x09"), array('', '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, "param2n", array( 1 => "an", "bn" => 2 ), false );?>


admin at sgssweb dot com

16 years ago


Surprizingly, debug_backtrace() cannot aquire arguments from the function that is used as the second or later argument of a function.

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


jlim#natsoft.com.my

19 years ago


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


spagmoid at yahoo dot NOSPAMcom

19 years ago


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


ciprian dot stingu at gmail dot com

11 years ago


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, $itw, 0);
                       
$ct = $it . $itw . ',';
                    }
                }
                else
                   
$ft .= LogVar($T['args'][0], '', $it, $itw, 0);
            }
           
$ft .= $it . ")r";
           
error_log($ft, 3, $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);
?>


aryel at iku dot com dot br

15 years ago


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


If you’ve spent any amount of time writing code, you’ll know that debugging is a vital part of the process. Sometimes it can be challenging to work out why your program has crashed or stopped working. It can be frustrating to encounter an error that doesn’t seem to make sense.

Knowing this, it’s wise to expand the tools in your debugging toolbox. When you add new tools and review well-used ones, you can make debugging quicker and more satisfying.

This article is about one such tool: the stack trace.

PHP logo stacked with Scalyr colors signifying PHP stack trace

What Is a Stack Trace?

I imagine you’ve seen a stack trace before. At first, it can look like an impenetrable block of jargon and code. It might resemble a list of statements, each seeming more meaningless than the last. Each point on the list may refer to a file you may never have known existed. In reality, this is the PHP interpreter trying to communicate what has gone wrong and help you fix it. It’s possible to understand this text and use it to make your programs better.

PHP_logo_stacked_with_Scalyr_colors_signifying_PHP_stack_trace

When your program is running, the PHP interpreter keeps track of which function is currently running. Not only that, but the interpreter also keeps track of which function called the current function, and so on, all the way down to the entry function of the program.

The interpreter does this using a data type called a stack. You can imagine it as a stack of cards. A card either goes on top or gets taken from the top.

For our case, we’re interested in the call stack. As your program calls a function, that function goes the top of the call stack. When the function returns, your program removes it from the top of that stack. So the stack trace is a list of the functions in the call stack at the point an exception is triggered.

Throwing an exception is how the interpreter tells you an error has happened. This could be from a mistyped variable, incorrect input, or any type of exception that you’ve defined in your code.

What Does the Stack Trace Look Like?

I’m going to use a simple procedural example to generate my stack trace. Traces from frameworks and your own more developed applications are likely to be longer. However, looking at the simplest version helps you understand more complex, real-world examples.

Here’s my script:

<?php

function divide_by_zero (int $number)
{
  return $number / 0;
}

echo(divide_by_zero(10));

I spent over a decade teaching secondary mathematics, so I can see this is going to cause a problem. Running the program gives me the following stack trace:

PHP Warning:  Division by zero in /home/kevinc/Documents/workspace/php/test.php on line 6
PHP Stack trace:
PHP   1. {main}() /home/kevinc/Documents/workspace/php/test.php:0
PHP   2. divide_by_zero() /home/kevinc/Documents/workspace/php/test.php:9

The trace starts with a PHP warning, which tries to explain what the problem is and where it happens. In my case, a “division by zero” error happened in line 6.

It’s important to read the stack trace in reverse order—in other words, from the bottom up. My stack has only two items. The function running at the point the program threw an exception is at the bottom. This is my helpfully named divide_by_zero function. Reading up a level, you can see the {main} function called this function, and the {main} function is the entry to the program. The number after the colon is the line number that the interpreter thinks the error has happened in. (Pro tip: Sometimes it’s useful to look one line back and make sure there’s a semicolon ending that line.)

Having the full trace is important. You can follow it like breadcrumbs back through your program. Your function may fail under certain circumstances only. Maybe it works most of the time, but when called in a particular chain, it fails. Seeing the chain of events that led to the error can help you unpick the problem.

How Does the Stack Trace Help With Debugging?

With the stack trace, it’s possible to work out the entire chain of events that led to the exception being thrown. Now that you know where the error has happened, you can add some logging. The error is happening on this line, so what’s the state of the program just before this? If your application is in production, you can export these logs to a service like Scalyr. Scalyr can aggregate these logs for you and allow you to get an overview of how often the error is happening.

Just as important: How about adding some logging in the functions further up the call stack? You now know every function involved in creating this particular error. With this information, you can run experiments and test ideas with more precision. There’s a helpful datasheet here to help think about how to manage your logs as the amount of data you collect increases.

Xdebug and IDE Integration

Xdebug is a popular tool that gives you more insight into what is happening while your code executes. It’s a PHP extension that lends a helping hand when you’re debugging your applications. This tool allows you to interact directly with running PHP scripts, allowing you to step through the program and observe what’s happening. With Xdebug, you can deal with problems that are complex and nuanced without relying solely on log statements. When integrated with your IDE, Xdebug allows your debugging to go up another level. You can integrate this tool with most code editors, including VSCode and even VIM.

With Xdebug set up and configured, you can set a breakpoint on the line where there’s an exception or error. Doing this allows you to interrupt the program and investigate. You’ll be able to see the live call stack and the variables currently in memory. You can execute commands and test ideas while the program is live. This is a powerful debugging technique.

Stack Trace Without Errors

With Xdebug, you can generate a stack trace at any point in your program. Maybe the program isn’t throwing an error, but it doesn’t seem to be working as you expected it to. Or, as mentioned earlier, you could have a function that works in certain circumstances but not in others.

Xdebug provides a set of debugging functions that you can put to good use. This one is the most useful for our needs:

xdebug_print_function_stack(string message);

Adding the command above will print the call stack, along with your message, without interrupting the program. You could add this to your temperamental function, allowing you to see the call stack—when it succeeds and when it fails. Combining these sets of information can help you identify issues more quickly.

You can read more about the other debugging functions that Xdebug provides in the documentation.

However, this kind of command in production can either confuse a user or give someone with malicious intent too much information. For this reason, it makes sense to ensure your production environment has display_errors set to Off in the live php.ini file.

Conclusion

I hope this brief article allows you to understand the stack trace and think a bit more about how you might use it. As I’ve mentioned, it’s a really helpful tool and can help you identify and solve errors quickly.

In local development, tools like Xdebug allow your debugging efforts to be truly effective. In your production environment, using logging and log aggregation can allow you to succeed there as well.

If you’re just getting started in collecting stack traces and logs, check out this workshop!

How to Debug PHP Errors

Debugging PHP errors in a production environment can be one of the single most frustrating experiences as a developer. More often than not, the error reports are vague, and identifying the underlying causes can be difficult at best. That said, there are a few common steps that can be followed towards identifying and resolving errors that crop up in production.

Debugging PHP Errors

Step 1: Increase the log level

More information is always better. Using the methods described in Where are PHP Errors Logged?, the first step towards diagnosing any issue is to increase the log level. This allows you to see everything that is happening before and after a problem occurs. There is a good chance that the problems you are experiencing have warnings or messages associated with them that don’t necessarily make it into the log files by default.

Step 2: Retain logs

Once you’ve increased the log level, the next step is to start retaining logs. This can be done through any number of log aggregation platforms, and allows you to start establishing a timeline of events without worrying about the log files being rolled over.

Step 3: Attempt to replicate circumstances

Once you’ve determined the log lines that relate to the problem at hand, the next step is to attempt to replicate the circumstances of the error in a development environment. Before we can do this, we first need to establish some testing guidelines. This involves doing things like mimicking the production database, the user accounts involved, and even the operating system. Everything is fair game here.

Step 4: Test assumptions

Once you’ve established the circumstances that you think might throw the exception or error you are hunting down, it’s time to test them. Never test exceptions in production. Development and staging environments are designed to be breakable without any impact on the end-users, so always always always try to break your code in a safe environment.

Step 5: Adjust test parameters and try again

If you were unable to replicate the problem in Step 4, then it’s back to the drawing board. Not every error is easy to reproduce, and may have time-based constraints or something else making it difficult to replicate in a non-production environment. Jump back to Step 3, adjust your test parameters, and try it all over again.

What is a stack trace?

Whenever exceptions are thrown, a stack trace is usually included. But, what is a stack trace? In essence, it is a rundown of every file and function that is called leading up to the error. To be clear, a stack trace doesn’t include the files and functions that are touched before the error occurred, only the chain of methods that are called as the error happened. This allows you to «trace» the «stack» of operations that are performed when an error happened in order to identify exactly what went wrong, and where.

As an example, let’s take a look at the stack trace that is returned from the following (incredibly simplistic) code:

do_the_thing();

function do_the_thing() {
  throw new Exception("a thing happened!");
}

When do_the_thing() is executed, an exception is immediately thrown. This results in the following stack trace:

Fatal error: Uncaught Exception: a thing happened! in test.php:6
Stack trace:
#0 test.php(3): do_the_thing()
#1 {main}
  thrown in test.php on line 6

As you can see, rather than simply returning the exception message, reading the stack trace in reverse order shows that the exception was thrown on line 6, but was triggered by a call to do_the_thing() on line 3. For more complicated stack traces, this can be invaluable as it gives us a lot of post-mortem information.

A brief introduction to Xdebug

While debugging in development can be difficult to do, Xdebug is a popular tool to help identify exactly what is happening as a piece of code executes. Containing a single-step debugger that allows you to interact directly with running PHP scripts, Xdebug is an excellent way to deal with highly complex and nuanced issues without having to resort to dangerous var_dump() and exit calls.

Example var_dump/exit call

Example var_dump/exit call

IDE integrations

While Xdebug is an incredibly powerful tool that can be used for more than just stepping through code, one of the more impressive aspects of it is the numerous IDE integrations that exist. These integrations give you the ability to diagnose problems with your code from directly within your editor, allowing you to test and fix problems in the environment you are most comfortable with.

Visual Studio Code XDebug Integration

Visual Studio Code XDebug Integration

Identifying patterns using Rollbar

Too often, debugging errors in a PHP application comes down to the amount of information you can eke out of your logs. Rollbar offers a better way because it empowers you to not only identify what is happening, but when, where, to whom, and how often. Rather than having to sort through pages of raw text logs, Rollbar aggregates data from individual exceptions and errors and creates a dashboard with as much information as possible for analyzing these issues.

Rollbar dashboard

When properly configured, these exceptions can be tied directly to user accounts, and tracked over time across an easy-to-read graph—with deployment markers to boot. While this doesn’t necessarily tell you exactly what an issue is, it comes as close as possible to doing so by providing you with more information than you could possibly ask for.

Occurrences

Occurrences

Whenever an exception is thrown during the course of an HTTP request, the request details are tracked alongside any additional information—such as the browser and operating system. This gives you the ability to identify any potential issues that could be related to specific systems, or even track down offending request parameters.

Suspected Deploy

Suspected deploy

If you are tracking deployments within Rollbar, then identifying which deployment might have been responsible for a new error or exception is as straightforward as possible—so straightforward, in fact, that Rollbar does the work for you.

Source Control Integration

Source control integration

When a Rollbar project is linked to a repository in GitHub, Bitbucket, or GitLab, any file references in a stack trace are automatically linked directly out to the offending file in the linked repository.

Returns the Exception stack trace.

This function has no parameters.

Returns the Exception stack trace as an array .

1) The trace does not include the file / line at which the exception is thrown; that entry is only recorded in the top-level getFile/Line methods.

2) Elements are returned in ‘closest-first’ order, e.g. if you have a script x which calls function y which calls function z which throws an exception, then the first trace element will be ‘Y’ and the second will be ‘X’.

If you are wanting to see the args within a stack trace on PHP 7.4, note that there is now a zend flag in the php.ini file that is default set to Off.

Set this flag to On and it will show the args again.

The order of the trace starts at the source of the exception and does not include main.
So for example:

throw new Exception ( ‘FATAL ERROR: bla bla. ‘ );

array(1) <
[0]=> array(6) <
[«file»]=> string(54) «/. /test.php»
[«line»]=> int(37)
[«function»]=> string(11) «__construct»
[«class»]=> string(4) «Test»
[«type»]=> string(2) «->»
[«args»]=> array(0) < >
>
>

$result = ‘Exception: «‘ ;
$result .= $e -> getMessage ();
$result .= ‘» @ ‘ ;
if( $trace [ 0 ][ ‘class’ ] != » ) <
$result .= $trace [ 0 ][ ‘class’ ];
$result .= ‘->’ ;
>
$result .= $trace [ 0 ][ ‘function’ ];
$result .= ‘();
‘ ;

Exception: «FATAL ERROR: bla bla. » @ Test->__construct();

debug_backtrace() generates a PHP backtrace.

This parameter can be used to limit the number of stack frames returned. By default ( limit = 0 ) it returns all stack frames.

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

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

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

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 ( «nt» , $result );
>
?>

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

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

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 ( $func , 0 , 7 ) == ‘include’ ) || ( substr ( $func , 0 , 7 ) == ‘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:

function debug ( $str ) <
echo get_caller_info () . $str . «
n» ;
>
?>

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

Just a short note on debug_backtrace options for PHP 5.3.6 or newer:

debug_backtrace() — show all options
debug_backtrace(0) — exlude [«object»]
debug_backtrace(1) — same as debug_backtrace()
debug_backtrace(2) — exlude [«object»] AND [«args»]

use this example and try calling debug_backtrace with different options

function F1 ()
<
echo «
» ;
echo «in F1 now» ;
echo «» ;
>

class DebugOptionsTest
<
function F2 ()
<
echo «
» ;
echo «in F2 now» ;
F1 ();
>

echo » calling F1″ ;
F1 ();

$c =new DebugOptionsTest ();
echo » calling F2″ ;
$c -> F2 ( «testValue» );

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.

// 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
?>

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

function myPrint ( $trace ) <
foreach( $trace as $i => $call ) <
/**
* THIS IS NEEDED! If all your objects have a __toString function it’s not needed!
*
* Catchable fatal error: Object of class B could not be converted to string
* Catchable fatal error: Object of class A could not be converted to string
* Catchable fatal error: Object of class B could not be converted to string
*/
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’ ]). ‘)’ ;
>

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

class B <
public function test () <
echo myPrint ( debug_backtrace ());
>
>

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

Quick and dirty formatted output from debug_backtrace.

foreach($file_paths AS $file_path) <
foreach($file_path AS $key => $var) <
if($key == ‘args’) <
foreach($var AS $key_arg => $var_arg) <
echo $key_arg . ‘: ‘ . $var_arg . ‘
‘;
>
> else <
echo $key . ‘: ‘ . $var . ‘
‘;
>
>
>

I want to point out that debug_backtrace() in new versions of php can detect recursion // circular references .. avoiding memory consumption.

class ParentClass <
public function __construct ()
<
$this -> _child = new ChildClass ( $this );
var_dump ( debug_backtrace ());
>
>

class ChildClass <
public function __construct ( ParentClass $p )
<
$this -> _parent = $p ;
>
>

$test = new ParentClass ();
?>

Output:

array(1) <
[0]=>
array(7) <
[«file»]=>
string(23) «/home/jcm/testdebug.php»
[«line»]=>
int(18)
[«function»]=>
string(11) «__construct»
[«class»]=>
string(11) «ParentClass»
[«object»]=>
object(ParentClass)#1 (1) <
[«_child»]=>
object(ChildClass)#2 (1) <
[«_parent»]=>
*RECURSION*
>
>
[«type»]=>
string(2) «->»
[«args»]=>
array(0) <
>
>
>

Attention in the *RECURSION* hint provided

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:

if ( count ( debug_backtrace ( FALSE , 1 )) == 0 )
<
// Do something
>
?>

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

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.

function bt ()
<
if( ! isRootIp () )
<
return false ;
>
array_walk ( debug_backtrace (), create_function ( ‘$a,$b’ , ‘print «
«. basename( $a[’file’] ). « <$a[‘line’]> <$a[‘function’]>() — «. dirname( $a[’file’] ). «/»;’ ) );
>
?>

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).

function get_caller_method ()
<
$traces = debug_backtrace ();

if (isset( $traces [ 2 ]))
<
return $traces [ 2 ][ ‘function’ ];
>

initialize
debug example.php> code-lines: 39-41 time: 2.0002 mem: 19 KB
debug example.php> code-lines: 41-44 time: 0.0000 mem: 19 KB
debug example.php> code-lines: 44-51 time: 0.6343 mem: 9117 KB
debug example.php> code-lines: 51-53 time: 0.1003 mem: 9117 KB
debug example.php> code-lines: 53-55 time: 0.0595 mem: 49 KB
*/

function debug()
<
static $start_time = NULL;
static $start_code_line = 0;

$call_info = array_shift( debug_backtrace() );
$code_line = $call_info[‘line’];
$file = array_pop( explode(‘/’, $call_info[‘file’]));

if( $start_time === NULL )
<
print «debug «.$file.»> initializen»;
$start_time = time() + microtime();
$start_code_line = $code_line;
return 0;
>

printf(«debug %s> code-lines: %d-%d time: %.4f mem: %d KBn», $file, $start_code_line, $code_line, (time() + microtime() — $start_time), ceil( memory_get_usage()/1024));
$start_time = time() + microtime();
$start_code_line = $code_line;
>

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

/*
* Send the output from a backtrace to the error_log
* @param string $message Optional message that will be sent the the error_log before the backtrace
*/
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’ ]));
>
>
>
?>

A usual entry looks like this:
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.

Another variation formatting backtrace.
Parameter $ignore to ignore the extra calls.
/**
* Getting backtrace
*
* @param int $ignore ignore calls
*
* @return string
*/
protected function getBacktrace ( $ignore = 2 )
<
$trace = » ;
foreach ( debug_backtrace () as $k => $v ) <
if ( $k $ignore ) <
continue;
>

$trace .= ‘#’ . ( $k — $ignore ) . ‘ ‘ . $v [ ‘file’ ] . ‘(‘ . $v [ ‘line’ ] . ‘): ‘ . (isset( $v [ ‘class’ ]) ? $v [ ‘class’ ] . ‘->’ : » ) . $v [ ‘function’ ] . ‘(‘ . implode ( ‘, ‘ , $v [ ‘args’ ]) . ‘)’ . «n» ;
>

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

diyism_trace.php:
( TRACES_MODE , ‘TEXTAREA’ ); //’TEXTAREA’ or ‘FIREPHP’
$GLOBALS [ ‘traces.pre’ ]=array();
function my_array_diff ( $arr1 , $arr2 )
$v )
>
>
return $arr1 ;
>
function my_var_export ( $var , $is_str = false )
< $rtn = preg_replace (array( ‘/Arrays+(/’ , ‘/[(d+)] =>(.*)n/’ , ‘/[([^d].*)] => (.*)n/’ ), array( ‘array (‘ , ‘1 => ’2» . «n» , ‘’1’ => ’2» . «n» ), substr ( print_r ( $var , true ), 0 , — 1 ));
$rtn = strtr ( $rtn , array( «=> ‘array (‘» => ‘=> array (‘ ));
$rtn = strtr ( $rtn , array( «)nn» => «)n» ));
$rtn = strtr ( $rtn , array( «‘n» => «‘,n» , «)n» => «),n» ));
$rtn = preg_replace (array( ‘/n +/e’ ), array( ‘strtr(’’, array(’ ’=>’ ’))’ ), $rtn );
$rtn = strtr ( $rtn , array( » Object’,» => » Object’ ));
if ( $is_str )
>
else
>
>
function tick_handler ()
< $tmp = debug_backtrace ();
$trace = my_array_diff ( $tmp , $GLOBALS [ ‘traces.pre’ ]);
//echo »;echo ‘
‘; //for debug diyism_trace.php
$trace = array_values ( $trace );
$GLOBALS [ ‘traces.pre’ ]= $tmp ;
if ( count ( $trace )> 0 && $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(.
= 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 ()
>
register_tick_function ( ‘tick_handler’ );
TRACES_MODE === ‘TEXTAREA’ ? register_shutdown_function ( ‘traces_output’ ): » ;
?>

test.php:
declare( ticks = 1 );
require ‘diyism_trace.php’ ;

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.

function dump ( $var ) <
$result = var_export ( $var , true );
$loc = whereCalled ();
return «n» ;
>

function whereCalled ( $level = 1 ) <
$trace = debug_backtrace ();
$file = $trace [ $level ][ ‘file’ ];
$line = $trace [ $level ][ ‘line’ ];
$object = $trace [ $level ][ ‘object’ ];
if ( is_object ( $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.

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:

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

:: 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.

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:

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;

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.

function var_format ( $v ) // pretty-print var_export
<
return ( str_replace (array( «n» , » » , «array» ),
array( «
» , » » , » array» ),
var_export ( $v , true )). «
» );
>
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 = «
MSG=’ $info ‘
» . var_format ( $_REQUEST ). «
» ;
$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 ( » » ,++ $sp ); //spaces(++$sp);
$trace .= «file= $file , line= $line , function= $function
» ;
>
$out .= «
» . backTrace ();
if( substr ( $info , 0 , 4 )== «XXX » ) // special errrors when db is inaccessible
<
$out = str_replace ( «
» , «n» , $out );
$out = str_replace ( » » , » » , $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

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.

foreach ( $arrTrace as $arr )
<
if (!isset ( $arr [ ‘file’ ]))
<
$arr [ ‘file’ ] = ‘[PHP Kernel]’ ;
>

Источник

debug_backtrace

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

debug_backtraceВыводит стек вызовов функций в массив

Описание

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

Список параметров

options

В версии 5.3.6, этот аргумент является битовой маской для следующих
настроек:

Настройки debug_backtrace()

DEBUG_BACKTRACE_PROVIDE_OBJECT Требуется или нет заполнять данные «объектов».
DEBUG_BACKTRACE_IGNORE_ARGS Требуется или нет не выводить данные с индексом «args», то есть
списки аргументов всех функций/методов, для уменьшения расхода
памяти.

До версии 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__
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.

Примеры

Пример #1 Пример использования debug_backtrace()


<?php
// filename: /tmp/a.phpfunction 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"
  }
}

Вернуться к: Функции обработки ошибок

PHP debug_backtrace() Function

Improve Article

Save Article

  • Read
  • Discuss
  • Improve Article

    Save Article

    The debug_backtrace() function is an inbuild function in PHP which is generally used by programmers in debugging. The main work of debug_backtrace() function is to generate the PHP backtrace i.e. to examine the stack trace. It returns an array of associate array of the backtrace PHP code. All possible returned elements by this function are –

    Name

    Type

    Description

    function string Name of the function in which debug_backtrace() function is being called.
    line integer Current line number of the function call.
    file string Name of the file where debug_backtrace() function has been called.
    class string Name of the class where debug_backtrace() function has been called.
    object object Name of the object which has been used to evoke the member function in which debug_backtrace() function is present.
    type string The type of current call . If the current call type is method call then , “->” is returned. If it is a static method call then, “::” is returned and If it is a function call then, nothing is returned.
    args array List of the Arguments present in the function definition. If the debug_backtrace() function is used within the file then all the files included within that is returned. 

    Syntax:

    array debug_backtrace(int $options, int $limit);

    Here, both the parameters $options and $limit are optional and are of integer type. The $option parameter is used for bitmask and $limit can be used to set limit the number of stack frame to be printed. Default value for the $limit is set to zero.

    Example: In this example, we have created a function that returns the sum of two input parameters and inside that debug_backtrace() function has been used. While printing the output first the sum of the input parameters will be displayed and then the backtrace of the code will be printed. 

    <?php

    function sum($a, $b) {

        echo $a + $b . "nn";

        var_dump(debug_backtrace());

    }

    sum(10,2);

    ?>

    Output

    12
    
    array(1) {
      [0]=>
      array(4) {
        ["file"]=>
        string(42) "/home/2228b7c9e401174a5f773007cd840e32.php"
        ["line"]=>
        int(9)
        ["function"]=>
        string(3) "sum"
        ["args"]=>
        array(2) {
          [0]=>
          int(10)
          [1]=>
          int(2)
        }
      }
    }

    Example 2: In this example, the concept of debug_backtrace() function has been implemented within the class along with the concept of recursion to check it’s back trace. In this example, two class i.e. BaseClass and DerivedClass has been created along with their constructors and inside the constructor of BaseClass debug_backtrace() has been called. The output generated i.e. back trace for this code consist of all the elements mentioned in the above table accordingly.

    PHP

    <?php

    class BaseClass {

        public function __construct() {

            $this->_child = new DerivedClass($this);

            var_dump(debug_backtrace());

        }

    }

    class DerivedClass {

        public function __construct(BaseClass $d) {

            $this->_parent = $d;

        }

    }

    $obj = new BaseClass();

    ?>

    Output

    array(1) {
      [0]=>
      array(7) {
        ["file"]=>
        string(42) "/home/ecdb752d3b6ec8ba97e6db84c42a5f2f.php"
        ["line"]=>
        int(18)
        ["function"]=>
        string(11) "__construct"
        ["class"]=>
        string(9) "BaseClass"
        ["object"]=>
        object(BaseClass)#1 (1) {
          ["_child"]=>
          object(DerivedClass)#2 (1) {
            ["_parent"]=>
            *RECURSION*
          }
        }
        ["type"]=>
        string(2) "->"
        ["args"]=>
        array(0) {
        }
      }
    }

    Reference: https://www.php.net/manual/en/function.debug-backtrace.php

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

    debug_backtrace — Generates a backtrace

    Description

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

    debug_backtrace() generates a PHP backtrace.

    Parameters

    options

    This parameter is a bitmask for the following options:

    debug_backtrace() options

    DEBUG_BACKTRACE_PROVIDE_OBJECT Whether or not to populate the «object» index.
    DEBUG_BACKTRACE_IGNORE_ARGS Whether or not to omit the «args» index, and thus all the function/method arguments, to save memory.
    limit

    This parameter can be used to limit the number of stack frames returned. By default (limit=0) it returns all stack frames.

    Return Values

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

    Possible returned elements from debug_backtrace()

    Name Type Description
    function string The current function name. See also __FUNCTION__.
    line int The current line number. See also __LINE__.
    file string The current file name. See also __FILE__.
    class string The current class name. See also __CLASS__
    object object The current object.
    type string The current call type. If a method call, «->» is returned. If a static method call, «::» is returned. If a function call, nothing is returned.
    args array If inside a function, this lists the functions arguments. If inside an included file, this lists the included file name(s).

    Examples

    Example #1 debug_backtrace() example

    <?php
    
    
    function a_test($str)
    {
        echo "nHi: $str";
        var_dump(debug_backtrace());
    }
    
    a_test('friend');
    ?>
    
    <?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"
      }
    }
    

    See Also

    • trigger_error() — Generates a user-level error/warning/notice message
    • debug_print_backtrace() — Prints a backtrace

    Понравилась статья? Поделить с друзьями:
  • Error ssl version or cipher mismatch chrome
  • Error ssl protocol error chromium gost
  • Error ssl protocol error bitrix
  • Error ssl peer certificate or ssh remote key was not ok insomnia
  • Error ssl intermediate chain is not valid