tap() es un helper que permite «usar un valor y devolverlo tal cual». Se utiliza cuando quieres intercalar un efecto colateral.La implementación en Illuminate\Support\helpers.php es simple.
function tap($value, $callback = null){ if (is_null($callback)) { return new HigherOrderTapProxy($value); } $callback($value); return $value;}
tap() ignora el valor de retorno de la callback. El resultado es siempre el valor original.
El uso más habitual: recibir un valor, procesarlo y devolverlo tal cual.
use App\Models\User;$user = tap(User::query()->latest()->firstOrFail(), function (User $model) { $model->update(['last_seen_at' => now()]);});// Se devuelve $user, sin importar lo que devuelva update()
Si omites la callback, se devuelve un HigherOrderTapProxy para encadenar directamente llamadas a métodos.
$updatedUser = tap($user)->update([ 'name' => $name, 'email' => $email,]);// Se devuelve la instancia User original, no el valor de retorno de update()
Con use del trait Illuminate\Support\Traits\Tappable añades el método tap() a tu clase.
trait Tappable{ public function tap($callback = null) { return tap($this, $callback); }}
Es decir, ofrece una versión de método de instancia de tap().
use Illuminate\Support\Traits\Tappable;class ReportBuilder{ use Tappable;}$builder = new ReportBuilder();$builder = $builder->tap(function (ReportBuilder $instance) { logger()->debug('builder initialized');});
Tappable es útil cuando quieres inyectar efectos colaterales en medio de una API fluida. Combinándolo con Macroable y Conditionable puedes construir builders extensibles al estilo Laravel.
1
Crea una clase fluida
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; }}
tap() / Tappable se usan también dentro del propio Laravel.
Illuminate\Routing\Router combina Macroable y Tappable.
En Router::respondWithRoute() se usa tap($route)->bind(...) sin callback, devolviendo $route tras ejecutar bind().
En Router::prepareResponse() se dispara un evento tras convertir la respuesta con tap(..., fn (...) => event(...)).
En Illuminate\Testing\Fluent\Concerns\Has se usa la cadena ->tap(...)->first(...)->etc() para asistir en las aserciones.
// 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));});
tap() es un helper pequeño por sí mismo, pero combinado con Macroable y Conditionable facilita construir las cadenas de métodos claras y legibles típicas de Laravel.