Search by

stevegrunwell / backtrace

stevegrunwell

Inspect and manipulate PHP backtraces

Package info

codeberg.org/stevegrunwell/backtrace

Issues

pkg:composer/stevegrunwell/backtrace

Statistics

Installs: 14

Dependents: 1

Suggesters: 0

v1.0.0 2026-09-09 17:11 UTC

This package is auto-updated.

Last update: 2026-09-09 15:24:28 UTC


README

This library provides strongly-typed, object representations of PHP backtraces, such as those you'd get from debug_backtrace().

These objects let you inspect, manipulate, and format backtraces for use in logs, metrics, and more:

echo Stack::factory(debug_backtrace())
    ->slice(2, 3)
    ->format('{file}:{line} {method}({args})');
#0 /path/to/some/file.php:18 SomeClass::someMethod(123, 'abc')
#1 /path/to/some/otherfile.php:97 SomeOtherClass->someOtherMethod('abc')
#2 /path/to/functions.php:14 some_function('abc')

Installation

BackTrace may be installed via Composer:

composer require stevegrunwell/backtrace

Usage

The most direct way to create a Stack instance is via Stack::factory(), which is a wrapper around debug_backtrace() (and accepts the same arguments):

use SteveGrunwell\BackTrace\Stack;

$stack = Stack::factory(DEBUG_BACKTRACE_PROVIDE_OBJECT);

The Stack::fromException() method works in the same way, but from a Throwable:

use SteveGrunwell\BackTrace\Stack;

$stack = Stack::fromException(new \RuntimeException());

Once you have a Stack instance, you can invoke other methods to inspect it.

Navigating stack frames

A Stack object is a collection of Frame objects, which can be accessed in several ways:

  1. Via the $stack->getFrames() method, which returns an array of Frame objects.
  2. Via each frame's index (e.g. $stack[2])
  3. Via $stack->offsetGet()

Formatting traces

Frame objects expose a format() method, which accepts a format string that will automatically replace the following placeholders:

PlaceholderMeaning
{args}Arguments passed to the function. Unlike other placeholders, this can also accept a maximum length for string arguments, e.g.: {$args:10}
{class}The class name
{file}The file name
{function}The function name
{line}The line number
{method}The full method name. An alias for {class}{type}{function}
{type}The type of method call, one of "::", "->", or an empty string (for functions)

For example, the default format string is {file}({line}): {class}{type}{function}({args}), which renders like this:

Some/File.php(123): SomeClass->someMethod(true, 'abc', Array, Object(ArrayIterator))

Similarly, the Stack class also defines a format() method (which calls Frame::format() for each frame under the hood) and includes an additional placeholder, {index}, that represents the position of the frame in the stack.

In practice, formatting a Stack looks like this:

$stack->format('#{index}: {method}({args}) in {file} on line {line}');

This will generate a string that looks like this:

#0: SomeClass->someMethod('abc', 123) in /path/to/some/file.php on line 12
#1: SomeOtherClass::someStaticMethod(123, Array) in /path/to/some/other/file.php on line 62
// ...

Stack::format() also accepts an optional second argument, $delimiter, which changes the delimiter between each frame in the stack. By default, this is a standard newline character.

If you need to explicitly include "{main}" in your printed trace (for example, to be consistent with Throwable::getTraceAsString()), you may also take advantage of Stack::format()'s third, $appendMain argument.

Parity with Throwable::getTraceAsString()

Every effort has been made to make it possible to create a formatted stack trace identical to those produced by Throwable::getTraceAsString():

$exception = new \RuntimeException();
$stack = Stack::fromThrowable($exception);

// These should be exactly the same.
$exception->getTraceAsString() === $stack->format(Stack::FORMAT_THROWABLE, PHP_EOL, true);

However, PHP allows the maximum length of string arguments to be modified via the zend.exception_string_param_max_len php.ini directive. If you're using a value other than the default (15), you may need to provide a custom format string with a different max-length if you require 100% parity:

// Same as Stack::FORMAT_THROWABLE
$default = '#{index} {file}({line}): {class}{type}{function}({args:15})';

// Customized to truncate string args after 8 characters:
$custom = '#{index} {file}({line}): {class}{type}{function}({args:8})';

Extracting a subset of frames

It's not uncommon to drop frames from the start or end of a stack, especially if they're unlikely to change (e.g. application bootstrapping, framework code, etc.).

BackTrace includes the Stack::slice() method, which works similarly to array_slice():

// Skip the first two frames, then set the maximum number of frames to 5.
$stack->slice(2, 5);

This can be especially useful if you're generating a Stack inside a method but don't want to include that method in the trace:

use SteveGrunwell\BackTrace\Stack;

protected function createBackTrace(): Stack
{
    // Slice off Stack::factory() and $this->createBackTrace().
    return Stack::factory()->slice(2);
}

License

BackTrace is available under the terms of the MIT License, a copy of which is included in this library.