stevegrunwell / backtrace
Inspect and manipulate PHP backtraces
Requires
- php: ^7.4 || ^8.0
- symfony/polyfill-php80: ^1.37
Requires (Dev)
- php: ^8.4
- phpcompatibility/php-compatibility: ^10.0.0@dev
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^13.0
- squizlabs/php_codesniffer: ^4.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
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:
- Via the
$stack->getFrames()method, which returns an array ofFrameobjects. - Via each frame's index (e.g.
$stack[2]) - Via
$stack->offsetGet()
Formatting traces
Frame objects expose a format() method, which accepts a format string that will automatically replace the following placeholders:
| Placeholder | Meaning |
|---|---|
{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.