with

Returns the given value, optionally passing it through a closure first.

Signature
with(mixed $value, ?callable $callback = null): mixed

Parameters

ParameterTypeDescription
$$valuemixedThe value to return or to hand to the callback.
$$callbackoptional?callable= nullInvoked with the value; its return value becomes the result.

Return value

mixedThe value itself when no callback is given, otherwise whatever the callback returns.

Errors

Nothing of its own; any exception raised inside the callback propagates unchanged.

with() returns whatever you give it. Supply a second argument and it calls that callable on the value and returns the callable's return value instead. The whole implementation is is_null($callback) ? $value : $callback($value).

When to reach for it

Two situations. First, running several statements against a freshly constructed object without naming a variable for it — the fluent-interface pattern the documentation shows with with(new Book, function (Book $book) { ... }). Second, collapsing a one-off derivation: with($row, fn (array $r) => ...) reads better inside an array literal than a temporary used exactly once.

What trips people up

It is not tap(). tap() runs the closure and hands back the original value; with() hands back the closure's value. A closure whose last statement is $model->save(); with no return gives you null, and that is by far the most common surprise. If you wanted the object back, use tap() or add an explicit return.

The callback always runs, even for null or an empty string. If you want it skipped for blank input, that is transform().

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Run a couple of setup statements on a newly constructed object without naming a variable.
  • Derive a value from an input inline inside an array literal.
  • Wrap a computed expression so you can keep reading left to right.

Frequently asked questions

What is the difference between with() and tap() in Laravel?

tap() returns the value you passed in and ignores the closure's return; with() returns the closure's return value and ignores the original. Use tap() when you want to keep chaining on the object, with() when you want the transformed result.

Does with() call the closure when the value is null?

Yes. with() has no blankness check at all — the callback runs for null, empty strings, empty arrays and everything else. If you want the callback skipped for blank values, use transform(), which guards on filled().

Is with() the same as Eloquent's with() for eager loading?

No, they are unrelated. The eager-loading with() is a method on the Eloquent query builder, called as Post::with('comments'); the helper documented here is a global function that takes a value and an optional closure.

More examples

with() versus tap()

Both closures mutate the same collection, but only tap() gives it back. $withed is NULL because the closure has no return statement — this is the single most reported confusion between the two helpers.

Example · php
<?php

use Illuminate\Support\Collection;

$collection = new Collection([1, 2, 3]);

// tap() returns the collection itself.
$tapped = tap($collection, function (Collection $c) {
    $c->push(4);
});

// with() returns whatever the closure returns — here, nothing.
$withed = with($collection, function (Collection $c) {
    $c->push(5);
});

var_dump($tapped instanceof Collection); // bool(true)
var_dump($withed);                       // NULL

Fluent setup on a new instance

This is the pattern the Laravel documentation demonstrates, with the explicit return added. Drop the return line and $book becomes null even though the model was saved correctly — the save happened, the value just was not passed back.

Example · php
<?php

use App\Models\Book;

$book = with(new Book, function (Book $book) {
    $book->title = 'Laravel';
    $book->author_id = 7;
    $book->save();

    return $book;   // without this, $book would be null
});

echo $book->title, "\n";   // Laravel

Inline derivation inside an array

Prints Array ( [name] => Ada Lovelace [age_in_1850] => 35 ). Each value is computed where it is used, so there is no temporary variable that exists only to be read once on the next line.

Example · php
<?php

$row = ['first' => 'Ada', 'last' => 'Lovelace', 'born' => 1815];

$payload = [
    'name' => with($row, fn (array $r) => trim($r['first'].' '.$r['last'])),
    'age_in_1850' => with($row['born'], fn (int $y) => 1850 - $y),
];

print_r($payload);

Discussion

  • Be the first to comment on this lesson.