> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Helper tap() y trait Tappable

> Uso y patrones de implementación del helper tap() de Laravel y del trait Illuminate\Support\Traits\Tappable.

## Qué es tap()

`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.

```php theme={null}
function tap($value, $callback = null)
{
    if (is_null($callback)) {
        return new HigherOrderTapProxy($value);
    }

    $callback($value);

    return $value;
}
```

```mermaid theme={null}
flowchart TD
    A["Se llama tap(value, callback)"] --> B{"¿callback es null?"}
    B -- Sí --> C["Devuelve un HigherOrderTapProxy"]
    B -- No --> D["Ejecuta callback(value)"]
    D --> E["Devuelve el value original"]
```

<Info>
  `tap()` ignora el valor de retorno de la callback. El resultado es siempre el valor original.
</Info>

## Uso básico

El uso más habitual: recibir un valor, procesarlo y devolverlo tal cual.

```php theme={null}
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.

```php theme={null}
$updatedUser = tap($user)->update([
    'name' => $name,
    'email' => $email,
]);

// Se devuelve la instancia User original, no el valor de retorno de update()
```

## Casos de uso frecuentes

### Intercalar salida de depuración

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

### Insertar logs o disparar eventos en medio de una cadena

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

### Ejecutar solo el efecto colateral sin cambiar el retorno

```php theme={null}
$response = tap($service->handle($request), function ($response) {
    \Illuminate\Support\Facades\Cache::increment('service_handle_success_total');
});
```

<Tip>
  Si quieres transformar el valor de retorno, usa `with()` o simplemente asignación normal. Reservar `tap()` para efectos colaterales facilita la lectura.
</Tip>

## Qué es el trait Tappable

Con `use` del trait `Illuminate\Support\Traits\Tappable` añades el método `tap()` a tu clase.

```php theme={null}
trait Tappable
{
    public function tap($callback = null)
    {
        return tap($this, $callback);
    }
}
```

Es decir, ofrece una versión de método de instancia de `tap()`.

```php theme={null}
use Illuminate\Support\Traits\Tappable;

class ReportBuilder
{
    use Tappable;
}

$builder = new ReportBuilder();

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

## Uso en el desarrollo de paquetes

`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.

<Steps>
  <Step title="Crea una clase fluida">
    ```php theme={null}
    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;
        }
    }
    ```
  </Step>

  <Step title="Usa Macroable, Conditionable y Tappable juntos">
    ```php theme={null}
    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();
    ```
  </Step>
</Steps>

Páginas relacionadas:

* [Trait Macroable](/es/advanced/macroable)
* [Trait Conditionable](/es/advanced/conditionable)
* [VOICEVOX for Laravel](/es/packages/laravel-voicevox) — ejemplo práctico en el que `TalkAudioQuery` o `SongAudioQuery` se ajustan con `tap()` antes de llegar a `generate()`.

## Ejemplos en el core de Laravel

`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.

```php theme={null}
// 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));
});
```

<Info>
  `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.
</Info>

## Próximos pasos

<Columns cols={2}>
  <Card title="Trait Macroable" icon="puzzle-piece" href="/es/advanced/macroable">
    Aprende el diseño para añadir métodos propios a clases existentes.
  </Card>

  <Card title="Trait Conditionable" icon="git-branch" href="/es/advanced/conditionable">
    Aprende las cadenas con bifurcación condicional mediante `when()` / `unless()`.
  </Card>
</Columns>


## Related topics

- [Trait InteractsWithData](/es/advanced/interacts-with-data.md)
- [Trait Dumpable](/es/advanced/dumpable.md)
- [Modo nativo: Talk (síntesis de voz desde texto) - VOICEVOX for Laravel](/es/packages/laravel-voicevox/native-talk.md)
- [Modo cliente: Talk (síntesis de voz desde texto) - VOICEVOX for Laravel](/es/packages/laravel-voicevox/client-talk.md)
- [Support Contracts (Arrayable / Jsonable / Htmlable / Responsable)](/es/advanced/support-contracts.md)
