Oh Dear is the all-in-one monitoring tool for your entire website. We monitor uptime, SSL certificates, broken links, scheduled tasks and more. You'll get a notifications for us when something's wrong. All that paired with a developer friendly API and kick-ass documentation. O, and you'll also be able to create a public status page under a minute. Start monitoring using our free trial now.

A better way to work with a backtrace in PHP

Original – by Freek Van der Herten – 4 minute read

To get the backtrace in PHP, you can use the debug_backtrace function. By default, it can be hard to work with. Using our newly released spatie/backtrace package, this becomes much simpler.

Let's dive in!

Why we created this package

The debug_backtrace is one of those PHP that has a terrible DX. It returns an array with frames, but those frames are hard to work with. Let's take a look at some example output.

0 => [
  "file" => "/Users/freek/dev/code/backtrace/src/Backtrace.php"
  "line" => 85
  "function" => "getRawFrames"
  "class" => "Spatie\Backtrace\Backtrace"
]
1 => [
  "file" => "/Users/freek/dev/code/backtrace/tests/BacktraceTest.php"
  "line" => 15
  "function" => "frames"
  "class" => "Spatie\Backtrace\Backtrace"
  "type" => "->"
]
2 =>[
  "file" => "/Users/freek/dev/code/backtrace/vendor/phpunit/phpunit/src/Framework/TestCase.php"
  "line" => 1536
  "function" => "it_can_create_a_backtrace"
  "class" => "Spatie\Backtrace\Tests\BacktraceTest"
]
// more frames

Looking at this output, you might think that it_can_create_a_backtrace is defined in /Users/freek/dev/code/backtrace/vendor/phpunit/phpunit/src/Framework/TestCase.php, but it's actually defined in the file of the previous frame: /Users/freek/dev/code/backtrace/tests/BacktraceTest.php

This is very confusing to work with, and this is the main reason we created a backtrace package. The output of our package will actually report frame properties as you expect them.

If you're a "professional" programmer, you might like to work with bitmasks.

debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS | DEBUG_BACKTRACE_PROVIDE_OBJECT)

As an "amateur" developer, I prefer to work with chainable method calls to configure things.

Working with spatie/backtrace

Here's how you can get the frames of the backtrace using our package:

// returns an array with `Spatie\Backtrace\Frame` instances
$frames = Spatie\Backtrace\Backtrace::create()->frames(); 

$firstFrame = $frames[0];

$firstFrame->file; // returns the file name
$firstFrame->lineNumber; // returns the line number
$firstFrame->class; // returns the class name
$firstFrame->method; // returns the method name

In all frames, we "fixed" the output of debug_backtrace: you'll always find the class and method a frame inside the file reported by the frame.

For performance reasons, the frames of the backtrace will not contain the arguments of the called functions. If you want to add those use the withArguments method.

$frames = Spatie\Backtrace\Backtrace::create()->withArguments()->frames();

$argumentsOfFirstFrame = $frames[0]->arguments // returns an array with arguments

If you only want to have the frames starting from a particular frame in the backtrace, you can use the startingFromFrame method:

use Spatie\Backtrace\Backtrace;
use Spatie\Backtrace\Frame;

$frames = Backtrace::create()
    ->startingFromFrame(function (Frame $frame) {
        return $frame->class === MyClass::class;
    })
    ->frames();

With this code, all frames before the frame that concerns MyClass will have been filtered out.

Alternatively, you can use the offSet method, which will skip the given number of frames. In this example, the first two frames will not end up in $frames.

$frames = Spatie\Backtrace\Backtrace::create()
    ->offset(2)
    ->frames();

To only get a specific number of frames, use the limit function. In this example, we'll only get the first two frames.

$frames = Spatie\Backtrace\Backtrace::create()
    ->limit(2)
    ->frames();

In closing

Our spatie/backtrace package makes working with a backtrace much more enjoyable. It contains a few more options. Head over to the readme on GitHub to learn more.

I've practiced YAGNI here and only added the bare minimum for now. We might add some helper methods to the Frame object in the future, so you can quickly check if a particular method is called statically or if the frame was added for a global function.

Be sure to take a look at this list of open source packages our team has previously made.

If you would like to support us, consider purchasing one of our paid products. At the moment of writing, we're having a Black Week sale where you can grab any of our products with a significant discount. Head over to our products page to know more.

Stay up to date with all things Laravel, PHP, and JavaScript.

You can follow me on these platforms:

On all these platforms, regularly share programming tips, and what I myself have learned in ongoing projects.

Every month I send out a newsletter containing lots of interesting stuff for the modern PHP developer.

Expect quick tips & tricks, interesting tutorials, opinions and packages. Because I work with Laravel every day there is an emphasis on that framework.

Rest assured that I will only use your email address to send you the newsletter and will not use it for any other purposes.

Comments

What are your thoughts on "A better way to work with a backtrace in PHP"?

Comments powered by Laravel Comments
Want to join the conversation? Log in or create an account to post a comment.