dd

Dumps the given variables with the var dumper and immediately ends the script.

Signature
dd(mixed ...$vars): never

Parameters

ParameterTypeDescription
$...$varsoptionalmixedAny number of values to dump, rendered in the order given. A named argument labels its dump with the argument name. Calling it with no arguments dumps a placeholder and still exits.

Return value

neverNothing — the script exits with status code 1 after the values are rendered.

Errors

It never throws — it calls exit(1), which skips shutdown code such as uncommitted database transactions, queued response middleware and remaining test assertions.

Changelog

  • PHP 12.xThe function is provided by symfony/var-dumper rather than the framework's own helper file; Laravel ships the package and registers the HTML/CLI dumper for you.

dd renders each value through the var dumper — collapsible HTML in the browser, colourised output on the console — and then terminates the process with exit(1). It is the fastest way to answer "what is actually in this variable at this line" without attaching a step debugger.

When to reach for it

  • Confirming the shape of a payload, a query result or a resolved model in the middle of a request.
  • Checking which branch of a condition is really taken.
  • Inspecting a value inside a pipeline, via the dd() method that Collection, Stringable and Fluent expose.

Use named arguments to label the output: dd(user: $user, input: request()->all()) prints each dump under its own name, which beats counting anonymous blocks.

What trips people up

The exit is the whole point and also the whole problem. Outside the CLI it first sends a 500 Internal Server Error header, so an API client sees a failed request with an HTML body rather than your dump. In a queue worker the job is marked failed; in a test the entire suite stops with exit code 1; inside a transaction nothing is committed. When you want the value and the rest of the request, use dump(), which prints and returns.

Example

Example · php
<?php

// app/Http/Controllers/CheckoutController.php
$cart = ['items' => 3, 'total' => 59.97];
$coupon = null;

echo "before", PHP_EOL;   // printed

dd($cart, $coupon);        // renders both, then exit(1)

echo "after", PHP_EOL;     // never reached

// before
// array:2 [
//   "items" => 3
//   "total" => 59.97
// ]
// null

When to use it

  • Check the exact keys of an inbound webhook payload before writing the parser.
  • Verify that a route-model-bound record is the one you expected.
  • Inspect the intermediate result of a collection chain with ->dd() partway through.
  • Confirm the merged input of a form submission when validation keeps failing.

Frequently asked questions

What is the difference between dd() and dump()?

Both render the same output, but dd() calls exit(1) and dump() returns. dump() gives back the value it was passed (and $this when called on a Collection or Stringable), so it can be dropped into an existing expression or chain without changing behaviour. Reach for dd() only when you want everything after that line to be skipped.

Why does my API return a 500 with HTML instead of my dump?

Because outside the CLI the function sends an "HTTP/1.1 500 Internal Server Error" header before dumping, whenever headers have not already been sent. An HTTP client sees a failed response whose body happens to contain the dumper's markup. Log the value instead, or inspect the raw response body.

How do I inspect a value inside a chain without breaking it?

Call ->dump() on the collection, string or fluent object at the point you want to see. Collections get dump()/dd() from the EnumeratesValues trait, which passes $this->all() to the global helpers, so you see the underlying array; Stringable and Fluent get them from the Dumpable trait, which dumps the object itself. Either way dump() returns $this, so the remaining methods still run, while ->dd() at the same spot prints and stops.

More examples

Labelled dumps, and the version that keeps going

Named arguments are the cheapest way to keep several dumps apart when you are comparing two structures. The dump() call shows the alternative when you need the request to finish — it returns the single value it was given, so it can be wrapped around an expression already in place.

Example · php
<?php

$user = ['id' => 3, 'email' => '[email protected]'];
$input = ['plan' => 'pro', 'seats' => '4'];

// Named arguments become labels in the output.
dd(user: $user, input: $input);

// user
// array:2 [ "id" => 3, "email" => "[email protected]" ]
// input
// array:2 [ "plan" => "pro", "seats" => "4" ]

// dump() prints the same thing and returns its argument,
// so it can sit inline without stopping anything:
$seats = (int) dump($input)['seats'];
echo $seats, PHP_EOL;   // 4

Stopping inside a collection pipeline

A Collection gets dump() and dd() from the EnumeratesValues trait, which forwards $this->all() to the global helpers — so the dump shows the underlying array rather than the Collection object. dump() returns $this, so the chain continues; swapping ->dump() for ->dd() here would show the same two rows and never compute the sum. Stringable and Fluent get the same pair of methods from the Dumpable trait, which dumps the object itself. Note that where() preserves the original keys 0 and 2.

Example · php
<?php

$orders = collect([
    ['id' => 1, 'total' => 20, 'status' => 'paid'],
    ['id' => 2, 'total' => 35, 'status' => 'refunded'],
    ['id' => 3, 'total' => 15, 'status' => 'paid'],
]);

$revenue = $orders
    ->where('status', 'paid')
    ->dump()              // prints the filtered items, carries on
    ->sum('total')
    ;

echo $revenue, PHP_EOL;

// array:2 [
//   0 => array:3 [ "id" => 1, "total" => 20, "status" => "paid" ]
//   2 => array:3 [ "id" => 3, "total" => 15, "status" => "paid" ]
// ]
// 35

Where it does real damage

exit(1) unwinds the process without running shutdown work: the transaction never commits, the queue worker records a failure, and in a test run PHPUnit stops with a non-zero status that looks like a broken build. Anywhere without a browser to render the dump — jobs, schedulers, CI — logging is the tool that actually helps.

Example · php
<?php

// app/Jobs/SyncInvoice.php
public function handle(): void
{
    DB::transaction(function () {
        $invoice = Invoice::create($this->payload);

        dd($invoice->toArray());   // exit(1) -> rollback, job marked failed

        $invoice->lines()->createMany($this->lines);
    });
}

// Safe alternatives that leave the process alive:
Log::debug('invoice', $invoice->toArray());
logger()->debug((string) collect($invoice->toArray()));
info('invoice created', ['id' => $invoice->id]);

echo 'job finished', PHP_EOL;

Discussion

  • Be the first to comment on this lesson.