debug_backtrace

Returns the current PHP call stack as an array of frames without halting execution.

Signature
debug_backtrace(int $options = DEBUG_BACKTRACE_PROVIDE_OBJECT, int $limit = 0): array
  • Added in PHP 4.3.0

Parameters

ParameterTypeDescription
$optionsoptionalint= DEBUG_BACKTRACE_PROVIDE_OBJECTBitmask of DEBUG_BACKTRACE_PROVIDE_OBJECT (populate the object index) and DEBUG_BACKTRACE_IGNORE_ARGS (omit the args index to save memory).
$limitoptionalint= 0Maximum number of stack frames to return. 0 means no limit.

Return value

arrayAn array of associative arrays, one per stack frame, each with some of the keys function, line, file, class, object, type and args. The array is ordered innermost frame first.

debug_backtrace() hands you the call stack as plain data, so you can log it, filter it, or attach it to a structured error record instead of dumping it to the screen. Reach for it inside logging helpers, deprecation shims, and custom error handlers where you need to know who called the code that is misbehaving.

Reading a frame correctly

This is where most people get confused. In a frame, function (plus class and type) describes the function that is executing, but file and line describe the call site — the place that function was called from. So frame 0 names the function containing your debug_backtrace() call, while its line number points at the caller. To answer “which file called me?” read [0]['file']; to answer “what is my caller's name?” read [1]['function'].

Keep it cheap

By default every frame carries the object it was called on and every argument that was passed. On a deep stack holding large objects that keeps references alive and can bloat memory or produce enormous log lines. Pass DEBUG_BACKTRACE_IGNORE_ARGS, and set $limit when you only need the nearest one or two frames.

Arguments passed by reference appear in args as references, so dumping them can surprise you.

Example

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

When to use it

  • Log the calling file and line alongside a deprecation warning in a library
  • Record a structured stack trace inside a custom error handler before writing JSON logs
  • Detect which subsystem triggered an expensive query in a debug-only profiler

Frequently asked questions

What is the difference between debug_backtrace and debug_print_backtrace?

debug_backtrace() returns the stack as an array you can inspect, filter, or log, while debug_print_backtrace() writes a formatted trace straight to output. Use the array version in production code and the printing version for throwaway debugging.

Why does debug_backtrace show the wrong line number?

It is not wrong — each frame's file and line are the location the frame's function was called from, not a line inside that function. Read the line from frame 0 to find where the current function was invoked.

How do I get a stack trace as a string without debug_backtrace?

Create an exception without throwing it and call getTraceAsString(): (new Exception())->getTraceAsString(). That gives a preformatted string, whereas debug_backtrace() gives you structured data you can reshape.

More examples

Identify the immediate caller

The limit of 2 keeps only the two innermost frames. Frame 1 is the function that called whoCalledMe(), so the output is "called by: repository". Using ?? '{main}' covers the case where the call came from top-level script code, where no function name exists.

Example · php
<?php
function whoCalledMe(): string {
    $frames = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
    return $frames[1]['function'] ?? '{main}';
}

function repository(): void {
    echo 'called by: ', whoCalledMe(), "\n";
}

function controller(): void {
    repository();
}

controller();

A deprecation notice that points at the caller

Frame 0 carries the file and line of the call into deprecated(), which is exactly the location a developer needs to fix. Requesting a limit of 1 means PHP never builds the rest of the stack.

Example · php
<?php
function deprecated(string $what): void {
    $caller = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0];
    echo "DEPRECATED: {$what} used in {$caller['file']} on line {$caller['line']}\n";
}

function oldApi(): void {
    deprecated('oldApi()');
}

oldApi();

Class and method frames

Method frames add class and type, where type is "->" for instance calls and "::" for static calls, so the first line prints Service->run. The final var_dump shows that at top level the backtrace is empty, so index 0 does not exist — always guard array access.

Example · php
<?php
class Service {
    public function run(): void {
        $f = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS)[0];
        echo $f['class'], $f['type'], $f['function'], "\n";
    }
}

(new Service())->run();
var_dump(isset(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS)[0]));

Discussion

  • Be the first to comment on this lesson.