Php show stack trace on error

debug_print_backtrace

debug_print_backtrace() prints a PHP backtrace. It prints the function calls, included/required files and eval() ed stuff.

Parameters

This parameter is a bitmask for the following options:

debug_print_backtrace() options
DEBUG_BACKTRACE_IGNORE_ARGS Whether or not to omit the «args» index, and thus all the function/method arguments, to save memory.

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

Return Values

Examples

Example #1 debug_print_backtrace() example

function c () debug_print_backtrace ();
>

// test.php file
// this is the file you should run

The above example will output something similar to:

#0 c() called at [/tmp/include.php:10] #1 b() called at [/tmp/include.php:6] #2 a() called at [/tmp/include.php:17] #3 include(/tmp/include.php) called at [/tmp/test.php:3]

See Also

User Contributed Notes 5 notes

Another way to manipulate and print a backtrace, without using output buffering:

// print backtrace, getting rid of repeated absolute path on each file
$e = new Exception ();
print_r ( str_replace ( ‘/path/to/code/’ , » , $e -> getTraceAsString ()));
?>

I like the output of debug_print_backtrace() but I sometimes want it as a string.

bortuzar’s solution to use output buffering is great, but I’d like to factorize that into a function. Doing that however always results in whatever function name I use appearing at the top of the stack which is redundant.

Below is my noddy (simple) solution. If you don’t care for renumbering the call stack, omit the second preg_replace().

function debug_string_backtrace () <
ob_start ();
debug_print_backtrace ();
$trace = ob_get_contents ();
ob_end_clean ();

// Remove first item from backtrace as it’s this function which
// is redundant.
$trace = preg_replace ( ‘/^#0\s+’ . __FUNCTION__ . «[^\n]*\n/» , » , $trace , 1 );

// Renumber backtrace items.
$trace = preg_replace ( ‘/^#(\d+)/me’ , ‘\’#\’ . ($1 — 1)’ , $trace );

If your show your error messages in HTML (with suitable safety using entities), this function won’t work nicely because it uses newlines for formatting.

Here is a function that works similarly, but using tags. Insert it near the beginning of your program to add a stack to Warning output only, or modify it as you like:

Читайте также:  Метод золотого сечения питон

// Here is code for error stack output in HTML:
function error_handler_callback($errno,$message,$file,$line,$context)
if ($errno === E_WARNING)
echo «Stack, innermost first:
«.nl2br((new Exception())->getTraceAsString());
return false; // to execute the regular error handler
>
set_error_handler(«error_handler_callback»);

Here’s a function that returns a string with the same information shown in debug_print_backtrace(), with the option to exclude a certain amount of traces (by altering the $traces_to_ignore argument).

I’ve done a couple of tests to ensure that it prints exactly the same information, but I might have missed something.

This solution is a nice workaround to get the debug_print_backtrace() information if you’re already using ob_start() in your PHP code.

function get_debug_print_backtrace ( $traces_to_ignore = 1 ) $traces = debug_backtrace ();
$ret = array();
foreach( $traces as $i => $call ) if ( $i < $traces_to_ignore ) continue;
>

$object = » ;
if (isset( $call [ ‘class’ ])) $object = $call [ ‘class’ ]. $call [ ‘type’ ];
if ( is_array ( $call [ ‘args’ ])) foreach ( $call [ ‘args’ ] as & $arg ) get_arg ( $arg );
>
>
>

$ret [] = ‘#’ . str_pad ( $i — $traces_to_ignore , 3 , ‘ ‘ )
. $object . $call [ ‘function’ ]. ‘(‘ . implode ( ‘, ‘ , $call [ ‘args’ ])
. ‘) called at [‘ . $call [ ‘file’ ]. ‘:’ . $call [ ‘line’ ]. ‘]’ ;
>

function get_arg (& $arg ) if ( is_object ( $arg )) $arr = (array) $arg ;
$args = array();
foreach( $arr as $key => $value ) if ( strpos ( $key , chr ( 0 )) !== false ) $key = » ; // Private variable found
>
$args [] = ‘[‘ . $key . ‘] => ‘ . get_arg ( $value );
>

$arg = get_class ( $arg ) . ‘ Object (‘ . implode ( ‘,’ , $args ). ‘)’ ;
>
>
?>

Источник

Exception::getTrace

Two important points about this function which are not documented:

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.

Читайте также:  Save html page online

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:

function Bar () throw new Exception ;
>

try Foo ();
> catch( Exception $e ) var_dump ( $e -> getTrace ());
>
?>

Will output:

When calling getTrace(), there is also the name of the class in returned array:

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

You can use this function to format a exception:

function MakePrettyException ( Exception $e ) $trace = $e -> getTrace ();

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

echo MakePrettyException ( $e );

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

Источник

Exception::getTraceAsString

Honestly, Exception::getTraceAsString() simply sucks, listing only the called method (below, for example, on line 89 function fail2() gets called, but there’s no information that you have the originator is fail1()). The fact that, in the example below, the exception gets thrown on line 78, is completely omitted from the trace and only available within the exception. Chained exceptions are not supported as well.

Example:
#0 /var/htdocs/websites/sbdevel/public/index.php(70): seabird\test\C->exc()
#1 /var/htdocs/websites/sbdevel/public/index.php(85): seabird\test\C->doexc()
#2 /var/htdocs/websites/sbdevel/public/index.php(89): seabird\test\fail2()
#3 /var/htdocs/websites/sbdevel/public/index.php(93): seabird\test\fail1()
#4

jTraceEx() provides a much better java-like stack trace that includes support for chained exceptions:
Exception: Thrown from class C
at seabird.test.C.exc(index.php:78)
at seabird.test.C.doexc(index.php:70)
at seabird.test.fail2(index.php:85)
at seabird.test.fail1(index.php:89)
at (main)(index.php:93)
Caused by: Exception: Thrown from class B
at seabird.test.B.exc(index.php:64)
at seabird.test.C.exc(index.php:75)
. 4 more
Caused by: Exception: Thrown from class A
at seabird.test.A.exc(index.php:46)
at seabird.test.B.exc(index.php:61)
. 5 more

(see at the end for the example code)

/**
* jTraceEx() — provide a Java style exception trace
* @param $exception
* @param $seen — array passed to recursive calls to accumulate trace lines already seen
* leave as NULL when calling this function
* @return array of strings, one entry per trace line
*/
function jTraceEx ( $e , $seen = null ) $starter = $seen ? ‘Caused by: ‘ : » ;
$result = array();
if (! $seen ) $seen = array();
$trace = $e -> getTrace ();
$prev = $e -> getPrevious ();
$result [] = sprintf ( ‘%s%s: %s’ , $starter , get_class ( $e ), $e -> getMessage ());
$file = $e -> getFile ();
$line = $e -> getLine ();
while ( true ) $current = » $file : $line » ;
if ( is_array ( $seen ) && in_array ( $current , $seen )) $result [] = sprintf ( ‘ . %d more’ , count ( $trace )+ 1 );
break;
>
$result [] = sprintf ( ‘ at %s%s%s(%s%s%s)’ ,
count ( $trace ) && array_key_exists ( ‘class’ , $trace [ 0 ]) ? str_replace ( ‘\\’ , ‘.’ , $trace [ 0 ][ ‘class’ ]) : » ,
count ( $trace ) && array_key_exists ( ‘class’ , $trace [ 0 ]) && array_key_exists ( ‘function’ , $trace [ 0 ]) ? ‘.’ : » ,
count ( $trace ) && array_key_exists ( ‘function’ , $trace [ 0 ]) ? str_replace ( ‘\\’ , ‘.’ , $trace [ 0 ][ ‘function’ ]) : ‘(main)’ ,
$line === null ? $file : basename ( $file ),
$line === null ? » : ‘:’ ,
$line === null ? » : $line );
if ( is_array ( $seen ))
$seen [] = » $file : $line » ;
if (! count ( $trace ))
break;
$file = array_key_exists ( ‘file’ , $trace [ 0 ]) ? $trace [ 0 ][ ‘file’ ] : ‘Unknown Source’ ;
$line = array_key_exists ( ‘file’ , $trace [ 0 ]) && array_key_exists ( ‘line’ , $trace [ 0 ]) && $trace [ 0 ][ ‘line’ ] ? $trace [ 0 ][ ‘line’ ] : null ;
array_shift ( $trace );
>
$result = join ( «\n» , $result );
if ( $prev )
$result .= «\n» . jTraceEx ( $prev , $seen );

Читайте также:  Среда разработки java jetbrains

return $result ;
>
?>

Here’s the example code:
class A public function exc () throw new \ Exception ( ‘Thrown from class A’ ); // >
>

class B public function exc () try $a = new A ;
$a -> exc (); // >
catch(\ Exception $e1 ) throw new \ Exception ( ‘Thrown from class B’ , 0 , $e1 ); // >
>
>
class C public function doexc () $this -> exc (); // >
public function exc () try $b = new B ;
$b -> exc (); // >
catch(\ Exception $e1 ) throw new \ Exception ( ‘Thrown from class C’ , 0 , $e1 ); // >
>
>

Источник

Оцените статью