Passer au contenu principal

Qu’est-ce que tap()

tap() est un helper qui permet « d’utiliser une valeur tout en la renvoyant telle quelle ». Il sert à insérer un effet de bord. L’implémentation dans Illuminate\Support\helpers.php est simple.
function tap($value, $callback = null)
{
    if (is_null($callback)) {
        return new HigherOrderTapProxy($value);
    }

    $callback($value);

    return $value;
}
tap() ignore la valeur retournée par le callback. La valeur retournée est toujours la valeur d’origine.

Utilisation de base

L’usage le plus courant : recevoir une valeur, la traiter, puis la renvoyer telle quelle.
use App\Models\User;

$user = tap(User::query()->latest()->firstOrFail(), function (User $model) {
    $model->update(['last_seen_at' => now()]);
});

// C'est $user qui est renvoyé, indépendamment de la valeur de retour d'update()
Sans callback, un HigherOrderTapProxy est renvoyé, ce qui permet d’enchaîner directement des appels de méthode.
$updatedUser = tap($user)->update([
    'name' => $name,
    'email' => $email,
]);

// L'instance User d'origine est renvoyée, pas la valeur de retour d'update()

Cas d’utilisation fréquents

Insérer une sortie de débogage

$result = tap($query->get(), function ($users) {
    logger()->debug('Fetched users', ['count' => $users->count()]);
});

Injecter des logs ou des événements dans une chaîne

$order = tap(Order::create($payload), function (Order $order) {
    event(new OrderCreated($order));
    logger()->info('Order created', ['id' => $order->id]);
});

Exécuter uniquement des effets de bord sans changer la valeur retournée

$response = tap($service->handle($request), function ($response) {
    \Illuminate\Support\Facades\Cache::increment('service_handle_success_total');
});
Si vous souhaitez transformer la valeur retournée, utilisez with() ou une affectation de variable classique. Réserver tap() aux effets de bord améliore la lisibilité.

Qu’est-ce que le trait Tappable

En faisant use Illuminate\Support\Traits\Tappable, vous ajoutez une méthode tap() à votre classe.
trait Tappable
{
    public function tap($callback = null)
    {
        return tap($this, $callback);
    }
}
Elle fournit donc une version méthode d’instance du helper tap().
use Illuminate\Support\Traits\Tappable;

class ReportBuilder
{
    use Tappable;
}

$builder = new ReportBuilder();

$builder = $builder->tap(function (ReportBuilder $instance) {
    logger()->debug('builder initialized');
});

Utilisation en développement de packages

Tappable est pratique pour glisser un effet de bord au milieu d’une API fluide. Associé à Macroable et Conditionable, vous pouvez créer un builder extensible dans l’esprit Laravel.
1

Créer une classe fluide

use Illuminate\Support\Traits\Conditionable;
use Illuminate\Support\Traits\Macroable;
use Illuminate\Support\Traits\Tappable;

class QueryPresetBuilder
{
    use Macroable;
    use Conditionable;
    use Tappable;

    protected array $filters = [];

    public function where(string $key, mixed $value): static
    {
        $this->filters[$key] = $value;

        return $this;
    }

    public function toArray(): array
    {
        return $this->filters;
    }
}
2

Combiner Macroable, Conditionable et Tappable

QueryPresetBuilder::macro('forActiveUsers', function () {
    /** @var QueryPresetBuilder $this */
    return $this->where('active', true);
});

$filters = (new QueryPresetBuilder)
    ->forActiveUsers()
    ->when($request->filled('role'), fn ($builder) => $builder->where('role', $request->role))
    ->tap(fn ($builder) => logger()->debug('current filters', $builder->toArray()))
    ->toArray();
Pages associées :

Utilisations dans le cœur de Laravel

Le cœur de Laravel utilise réellement tap() / Tappable.
  • Illuminate\Routing\Router combine Macroable et Tappable.
  • Router::respondWithRoute() utilise tap($route)->bind(...) sans callback : après l’exécution de bind(), la $route d’origine est renvoyée.
  • Router::prepareResponse() utilise tap(..., fn (...) => event(...)) pour déclencher un événement après la conversion de la réponse.
  • Illuminate\Testing\Fluent\Concerns\Has implémente une aide aux assertions via la chaîne ->tap(...)->first(...)->etc().
// Extrait de Illuminate\Routing\Router
$route = tap($this->routes->getByName($name))->bind($this->currentRequest);

return tap(static::toResponse($request, $response), function ($response) use ($request) {
    $this->events->dispatch(new ResponsePrepared($request, $response));
});
Pris isolément, tap() est un petit helper, mais combiné à Macroable et Conditionable, il facilite l’écriture de chaînes de méthodes lisibles très fréquentes dans Laravel.

Étapes suivantes

Trait Macroable

Découvrez la conception permettant d’ajouter des méthodes personnalisées aux classes existantes.

Trait Conditionable

Découvrez les chaînes conditionnelles via when() / unless().
Dernière modification le 13 juillet 2026