An important part of every Laravel developer's debugging arsenal is the humble dd()
helper function—"dump and die"—to output the contents of a variable and terminate execution of your code. In the browser, dd()
results in a structured, easy-to-read tree, complete with little arrow buttons that can be clicked to expand or hide children of nested structures. In the terminal, however, it's a different story.
When doing a lot of testing, we end up spending a quite a bit of time inspecting output in the terminal, rather than in the browser. Often, while troubleshooting a failing test in PHPUnit, you'll find the need to dd()
the value of an array or collection, the contents of some class or an Eloquent model, or to inspect the JSON response from an API call. The command line output of dd()
is structured the same as the HTML—but many times, the output zooms by and is either very long or deeply nested, leading to a whole lot of scrolling to hunt down the information you were looking for. Finding the top of the output can be difficult, or in some cases impossible, if the output length exceeds your terminal's buffer.
Fortunately, it's simple to build your very own customized version of dd()
to help tame your unwieldly terminal output—helping you find the details you're interested in quickly, without wearing out your trackpad (and your patience). With just one helper function, you can go from this:
...to this:
...or anything in between.
There are two ways to go about this:
Since version 5, Laravel's dd()
(and it's cousin, dump()
, which doesn't halt execution) has relied on Symfony's VarDumper
component under the hood. So the easiest way to supercharge your dd()
is to write a helper function that gives you access to some of the additional configuration methods in VarDumper.
An easy place for this helper function to live is within a helpers.php
file in your app
directory, which you can autoload by adding it to composer.json
:
"autoload": { "files": [ "app/helpers.php" ],},...
You can store other helper functions here as well, modeled after Laravel's
/Illuminate/Foundation/helpers.php
file. If you're only adding functions related to development, the file can be autoloaded under theautoload-dev
key. In addition, if you wish to actually override Laravel'sdd()
function (or any other Laravel helper function, for that matter) rather than using a different name for your customized function, you would need torequire
your helper file in/bootstrap/autoload.php
before the linerequire __DIR__.'/../vendor/autoload.php'
.
In your new app/helpers.php
file, we'll create a new function called ddd()
, which will accept the variable we wish to dump, along with whatever other parameters we want to use to customize our output. As a starting point, let's start with a bare-bones function that just mimics the behavior of the built-in dd()
:
<?php use Illuminate\Support\Debug\HtmlDumper;use Symfony\Component\VarDumper\Cloner\VarCloner;use Symfony\Component\VarDumper\Dumper\CliDumper; function ddd($variable){ $cloner = new VarCloner(); $dumper = 'cli' === PHP_SAPI ? new CliDumper() : new HtmlDumper(); $dumper->dump($cloner->cloneVar($variable)); die(1);}
VarDumper
works by first cloning the input variable with a "Cloner", then dumping it to either the browser or the terminal with with a "Dumper". The VarCloner
class, and the Data
object that it creates, both have some very handy configuration options that we can now take advantage of. On the cloner,
setMaxString()
will truncate long strings to the specified length. setMaxItems()
will limit the number of items that get displayed past the first nesting level; for example, setMaxItems(6)
will turn this output:
array:2 [ 0 => array:5 [ "id" => 1 "foo" => "FooValue1" "bar" => "BarValue1" "baz" => "BazValue1" "qux" => array:2 [ "average" => 3.0 "standard_deviation" => 1.0 ] ] 0 => array:5 [ "id" => 1 "foo" => "FooValue2" "bar" => "BarValue2" "baz" => "BazValue2" "qux" => array:2 [ "average" => 5.0 "standard_deviation" => 1.0 ] ] ...
into this:
array:2 [ 0 => array:5 [ "id" => 1 "foo" => "FooValue1" "bar" => "BarValue1" "baz" => "BazValue1" "qux" => array:2 [ …2] ] 1 => array:5 [ "id" => 2 …4 ] ...
...which, in the case of very long output, is a great way to get a quick look at just the top few items. (Note that passing a value of -1
to any of these configuration methods is the equivalent of having no limit on the output.)
The results of VarCloner
can be further modified before they are dumped. The method withMaxItemsPerDepth()
will limit the number of items that are displayed at each level of depth, while withMaxDepth()
—which I've found to be most useful for whipping your output into shape—will limit the number of nested child levels that are displayed in their expanded form. In the example above, a setting of withMaxDepth(2)
would collapse all the qux
arrays, giving us:
array:2 [ 0 => array:5 [ "id" => 1 "foo" => "FooValue1" "bar" => "BarValue1" "baz" => "BazValue1" "qux" => array:2 [ …2] ] 1 => array:5 [ "id" => 1 "foo" => "FooValue2" "bar" => "BarValue2" "baz" => "BazValue2" "qux" => array:2 [ …2] ] ...
Going back to our helper function, we can accept some parameters that will give us on-the-fly control of how our ddd()
output is displayed:
function ddd($variable, $depth = -1, $stringLength = 20){ $cloner = new VarCloner(); $cloner->setMaxString($stringLength); $dumper = 'cli' === PHP_SAPI ? new CliDumper() : new HtmlDumper(); $dumper->dump($cloner->cloneVar($variable)->withMaxDepth($depth)); die(1);}
So now, if we call ddd($someVariable, 2)
our output will be limited to two levels deep, with long strings truncated to 20 characters. If we don't get enough detail to find what we're looking for, we can very simply drop down a level with ddd($someVariable, 3)
. It's a quick and easy way to whip your debugging output into shape, particularly when inspecting deeply-nested JSON objects or a long Eloquent model.
An alternative is to use the debugging library Kint to accomplish the same thing, but with slightly different results. Kint offers some really handy enhancements out-of-the-box for controlling debugging output in your browser, but like VarDumper, it gives access to two configuration options for terminal output that are useful: $maxLevels
and $maxStrLength
.
First, install Kint using composer:
composer require raveren/kint
Then, in the app/helpers.php
file we created earlier, we can make a custom function called debug
:
function debug($variable, $depth = null){ \Kint::$maxLevels = $depth; return ddd($variable);}
Note: Kint includes its own functions named
ddd()
anddump()
, so we need to use a new name; ourdebug()
function calls Kint's built-inddd()
function.
And just like that, we can call debug($someVariable, 3)
to cut our output down to size again. Like VarDumper, Kint's output is nicely formatted and color-coded; one advantage to using Kint in place of VarDumper is that Kint's output includes more details about data types in its results, making it very easy to spot when some value that should be an integer
is actually a float
, for instance.
Do you have your own great tips for tricking out your testing setup? Share them with us on Twitter at @TightenCo.
We appreciate your interest.
We will get right back to you.