PHP Doku:: Erzeugt Daten zur Ablaufverfolgung - function.debug-backtrace.html

Verlauf / Chronik / History: (48) anzeigen

Sie sind hier:
Doku-StartseitePHP-HandbuchFunktionsreferenzDas Verhalten von PHP beeinflussenFehlerbehandlung und ProtokollierungFehlerbehandlungsfunktionendebug_backtrace

Ein Service von Reinhard Neidl - Webprogrammierung.

Fehlerbehandlungsfunktionen

<<Fehlerbehandlungsfunktionen

debug_print_backtrace>>

debug_backtrace

(PHP 4 >= 4.3.0, PHP 5)

debug_backtraceErzeugt Daten zur Ablaufverfolgung

Beschreibung

array debug_backtrace ([ bool $provide_object = true ] )

debug_backtrace() erzeugt Daten zur Ablaufverfolgung.

Parameter-Liste

provide_object

Legt fest, ob der "Objekt"-Index befüllt wird. Standardwert ist TRUE.

Rückgabewerte

Gibt ein assoziatives Array zurück. Als zurückgegebene Arrayelemente von debug_backtrace() sind möglich:

Mögliche Rückgabewerte von debug_backtrace()
Name Typ Beschreibung
function string Der Name der aktuell ausgeführten Funktion. Siehe auch __FUNCTION__.
line integer Die aktuelle Zeilennummer. Siehe auch __LINE__.
file string Der aktuelle Dateiname. Siehe auch __FILE__.
class string Der aktuelle class - Name. Siehe auch __CLASS__.
object object Das aktuelle Objekt.
type string Der aktuelle Typ des Aufrufs. Falls der Aufruf in einer Methode erfolgte, wird "->" zurückgegeben. Falls der Aufruf aus einer statischen Funktion erfolgte, wird "::" zurückgegeben und falls der Aufruf aus einer Funktion erfolgte, wird nichts zurückgegeben.
args array Falls der Aufruf aus einer Funktion erfolgte, werden hier die Funktionsargumente aufgelistet. Falls der Aufruf aus einer eingebundenen Datei erfolgte, werden die Namen der Include-Dateien angegeben.

Changelog

Version Beschreibung
5.2.5 Der optionale Parameter provide_object wurde hinzugefügt.
5.1.1 Aktuelles object als möglichen Rückgabewert hinzugefügt.

Beispiele

Beispiel #1 debug_backtrace()-Beispiel

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

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

a_test('friend');
?>

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

Ergebnisse beim Aufruf von /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"
  }
}

Siehe auch


30 BenutzerBeiträge:
- Beiträge aktualisieren...
Bill Getas
21.12.2010 12:09
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\'] ). "/";' ) );
}
?>
henzeberkheij at gmail dot com
10.10.2010 11:07
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;
kenorb at gmail dot com
7.09.2010 16:11
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\']}); ";'));
?>
php noob
3.09.2010 5:32
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( $var, true );
   
$loc = whereCalled();
    return
"\n<pre>Dump: $loc\n$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.
jlammertink at gmail dot com
15.07.2010 11:32
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;
}
?>
Lachlan McDowall
23.04.2010 13:11
This can be used to show if a file is being accessed directly or being included/called from another:

<?php
if (count(debug_backtrace()) == 0){
 
// Do something
}
?>
john dot risken at gmail dot com
26.02.2010 7:02
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
michael dot schramm at gmail dot com
20.10.2009 9:29
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);

?>
frank at frank dot com
7.05.2008 20:12
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
11.02.2008 9:04
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 :)
aryel at iku dot com dot br
29.01.2008 23:40
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
misterpib at gmail dot com
17.10.2007 18:35
You should probably try to avoid changing any of the items in the args array. Consider this example:
----------
function a(&$value)
{
  echo "start a: $value\n";
  b();
  echo "end a: $value\n";
}

function b()
{
  echo "start b\n";
  $stack = debug_backtrace();
  $stack[1]['args'][0] = 'bob';
  echo "end b\n";
}

$mynum = 42;
a($mynum);
--------------

This prints:

start a: 42
start b
end b
end a: bob
php at kennel17 dot co dot uk
20.06.2007 18:30
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.
php at kennel17 dot co dot uk
20.06.2007 18:01
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.
jsnell at e-normous dot com
30.05.2007 23:35
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)
kroczu AT interia DOT pl
23.01.2007 19:24
<?
// 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."> 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), 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();

?>
seaside dot ki at mac dot com
15.12.2006 1:20
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
23.09.2006 18:34
A simple python-like backtrace. Note that I don't recurse into arrays if they are passed as arguments to functions.

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

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

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

<?php

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

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

trace( 'error outside function' );

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

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

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

<?php

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

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

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

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

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

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

To use it, simply do something like this:

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

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

<?php

$arrTrace
= debug_backtrace();

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

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

   
// Do something
}

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

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

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

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

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

Which produces something like:

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

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

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

<?php

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

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

?>

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

Backtrace:

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

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

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

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

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

Great function, but you have a few bugs.

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

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

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

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

and substitute accordingly.

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

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

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

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

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

            echo ' -- ';

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

            echo $t['function'];

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

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

Enjoy, John Lim

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



PHP Powered Diese Seite bei php.net
The PHP manual text and comments are covered by the Creative Commons Attribution 3.0 License © the PHP Documentation Group - Impressum - mail("TO:Reinhard Neidl",...)