debug_print_backtrace

Prints the current PHP call stack straight to the output for quick debugging.

Signature
debug_print_backtrace(int $options = 0, int $limit = 0): void
  • Added in PHP 5.0

Parameters

ParameterTypeDescription
$optionsoptionalint= 0Bitmask; DEBUG_BACKTRACE_IGNORE_ARGS omits arguments from the printed frames. DEBUG_BACKTRACE_PROVIDE_OBJECT is accepted for compatibility but has no effect.
$limitoptionalint= 0Maximum number of stack frames to print. 0 prints all frames.

Return value

voidNo value is returned; the trace is written to the standard output.

It prints numbered frames — #0 /path/file.php(12): inner() — with no return value and no need to wrap anything in print_r(). (The php.net example output still shows the pre-PHP-7 format "#0 c() called at [/tmp/include.php:10]"; on PHP 8.x the actual format is "#N file(line): function()", matching Throwable::getTraceAsString(). Verified on PHP 8.5.9 and 8.3.31, no Xdebug loaded.)

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Find out why a callback or event listener is firing more than once
  • Trace which code path reached a slow database call during local debugging
  • Print the call chain from inside a recursive function to see how deep it went

Frequently asked questions

How do I print a PHP stack trace without throwing an exception?

Call debug_print_backtrace() at the point of interest; it prints the current call stack and execution continues normally. Nothing is thrown and no error is raised.

Why is debug_print_backtrace not showing anything?

Either it was called at the top level of a script, where there are no function frames to print, or output buffering is swallowing the text. Check with ob_get_level() or capture the output with ob_start().

Can I send debug_print_backtrace output to a log file instead of the screen?

Not directly — it always writes to output. Wrap it in ob_start() and ob_get_clean() to get the trace as a string, then log that string.

More examples

Limit the trace to the nearest frames

Without the limit the trace would show c, b, a and the top-level call. Passing 2 stops after frames #0 and #1, which is usually all you need and keeps deep recursion from flooding the screen.

Example · php
<?php
function c(): void { debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2); }
function b(): void { c(); }
function a(): void { b(); }

echo "only two frames:\n";
a();

Capture the trace into a string

Output buffering intercepts what the function prints, so the trace becomes an ordinary string. The strtoupper() call proves the text was captured rather than echoed directly, which is how you would route it into a log line.

Example · php
<?php
function failing(): string {
    ob_start();
    debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
    return trim(ob_get_clean());
}

function caller(): void {
    echo strtoupper(failing()), "\n";
}

caller();

Arguments shown versus hidden

The first trace lists the arguments in the frame, the second omits them entirely. Note that since PHP 8.0 the ini setting zend.exception_string_param_max_len defaults to 0, so string arguments are rendered as '...' rather than their literal values — the actual PHP 8.5 output is "#0 /path/file.php(9): target('...', '...')" followed by "#0 /path/file.php(9): target()". The token is only exposed if zend.exception_string_param_max_len is raised, but non-string arguments (ints, floats, object class names) are always shown, so DEBUG_BACKTRACE_IGNORE_ARGS is still the safer default in anything a user might see.

Example · php
<?php
function target(string $user, string $token): void {
    echo "with args:\n";
    debug_print_backtrace();
    echo "without args:\n";
    debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
}

target('alice', 'secret-token-123');

Discussion

  • Be the first to comment on this lesson.