Oh Dear! monitors your entire website, not just the homepage. You'll get a notification as soon as your website is down, a monthly uptime report, a warning a few days before your SSL certificate expires and much more! Start your free 10 day 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.

Follow me on Twitter. I regularly tweet out programming tips, and what I myself have learned in ongoing projects.

Every two weeks 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

Webmentions

MaXyC Webber liked on 25th November 2020
Cyril de Wit liked on 25th November 2020
Asif Mulla liked on 25th November 2020
William liked on 25th November 2020
De Gracia Mathieu liked on 24th November 2020
PHPTrends retweeted on 24th November 2020
Wyatt liked on 24th November 2020
René Sinnbeck liked on 24th November 2020
Tauseef shah liked on 24th November 2020
Songhua Hu liked on 24th November 2020
Niko Halink liked on 24th November 2020
Moath liked on 24th November 2020
mel liked on 24th November 2020
✪ Roberto Inetti ✪ replied on 24th November 2020
OMG I was writing a custom debugging class just a couple of hours ago. I will give this a try. Thank you!
Ihor Vorotnov liked on 24th November 2020
Bruno CHIREZ liked on 24th November 2020
. liked on 24th November 2020
Tony Messias liked on 24th November 2020
Sumon Molla Selim, FRSA liked on 24th November 2020
Brenier Arnaud liked on 24th November 2020
Andrew Broberg liked on 24th November 2020
Florian Voutzinos liked on 24th November 2020
Mitchell Johnson 🛠 liked on 24th November 2020
Andre Sayej liked on 24th November 2020
Kevin Purwito liked on 24th November 2020
Andrés Herrera García liked on 24th November 2020
/dev/caneco liked on 24th November 2020