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

# tap()-Helper und Tappable-Trait

> Verwendung und Implementierungsmuster des Laravel-Helpers tap() sowie des Traits Illuminate\Support\Traits\Tappable.

## Was ist tap()?

`tap()` ist ein Helper, der „einen Wert benutzt und ihn dennoch unverändert zurückgibt". Er kommt zum Einsatz, wenn Sie einen Seiteneffekt einschleifen möchten.

Die Implementierung in `Illuminate\Support\helpers.php` ist schlicht:

```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["tap(value, callback) aufrufen"] --> B{"Ist callback null?"}
    B -- Ja --> C["HigherOrderTapProxy zurückgeben"]
    B -- Nein --> D["callback(value) ausführen"]
    D --> E["Ursprünglichen value zurückgeben"]
```

<Info>
  `tap()` ignoriert den Rückgabewert des Callbacks. Zurückgegeben wird stets der ursprüngliche Wert.
</Info>

## Grundlegende Verwendung

Der grundlegendste Einsatz besteht darin, den Wert zu übernehmen, etwas damit zu tun und ihn unverändert zurückzugeben.

```php theme={null}
use App\Models\User;

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

// Zurückgegeben wird $user – unabhängig vom Rückgabewert von update()
```

Ohne Callback erhalten Sie einen `HigherOrderTapProxy` — so lässt sich der Methodenaufruf direkt anfügen.

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

// Zurückgegeben wird nicht der Rückgabewert von update(), sondern die ursprüngliche User-Instanz
```

## Typische Einsatzstellen

### Debug-Ausgabe einfügen

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

### Logging oder Event-Versand innerhalb der Chain einfügen

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

### Seiteneffekte ausführen, ohne den Rückgabewert zu verändern

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

<Tip>
  Wollen Sie den Rückgabewert transformieren, nutzen Sie `with()` oder eine gewöhnliche Variablenzuweisung. Beschränken Sie `tap()` auf Seiteneffekte — das steigert die Lesbarkeit.
</Tip>

## Was ist der Tappable-Trait?

Wenn Sie `Illuminate\Support\Traits\Tappable` per `use` einbinden, erhält Ihre Klasse eine `tap()`-Methode.

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

Kurz gesagt bietet der Trait lediglich eine Instanzmethoden-Variante von `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');
});
```

## Einsatz in der Paketentwicklung

`Tappable` ist praktisch, wenn Sie in einer Fluent API einen Seiteneffekt einbauen möchten. In Kombination mit `Macroable` und `Conditionable` bauen Sie einen Laravel-typischen, erweiterbaren Builder.

<Steps>
  <Step title="Eine Fluent-Klasse anlegen">
    ```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="Macroable, Conditionable und Tappable kombiniert nutzen">
    ```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>

Verwandte Seiten:

* [Macroable-Trait](/de/advanced/macroable)
* [Conditionable-Trait](/de/advanced/conditionable)
* [VOICEVOX for Laravel](/de/packages/laravel-voicevox) — Praxisbeispiel, in dem `TalkAudioQuery` und `SongAudioQuery` per `tap()` angepasst und anschließend an `generate()` weitergegeben werden

## Verwendung im Laravel-Kern

Auch im Laravel-Kern selbst kommen `tap()` und `Tappable` zum Einsatz.

* `Illuminate\Routing\Router` verwendet `Macroable` und `Tappable` gemeinsam.
* In `Router::respondWithRoute()` wird ohne Callback `tap($route)->bind(...)` genutzt und die ursprüngliche `$route` auch nach `bind()` zurückgegeben.
* In `Router::prepareResponse()` wird nach der Response-Konvertierung mit `tap(..., fn (...) => event(...))` ein Event ausgelöst.
* In `Illuminate\Testing\Fluent\Concerns\Has` unterstützt der Aufruf `->tap(...)->first(...)->etc()` die Assertions.

```php theme={null}
// Aus 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>
  Für sich genommen ist `tap()` ein kleiner Helper — in Kombination mit `Macroable` und `Conditionable` entstehen jedoch gut lesbare Method-Chains, wie man sie in Laravel häufig sieht.
</Info>

## Nächste Schritte

<Columns cols={2}>
  <Card title="Macroable-Trait" icon="puzzle-piece" href="/de/advanced/macroable">
    Lernen Sie das Design kennen, mit dem Sie bestehende Klassen um eigene Methoden erweitern.
  </Card>

  <Card title="Conditionable-Trait" icon="git-branch" href="/de/advanced/conditionable">
    Lernen Sie Bedingungs-Chains mit `when()` / `unless()` kennen.
  </Card>
</Columns>


## Related topics

- [InteractsWithData-Trait](/de/advanced/interacts-with-data.md)
- [Native-Modus: Talk (Text-Sprachsynthese) - VOICEVOX für Laravel](/de/packages/laravel-voicevox/native-talk.md)
- [Client-Modus: Talk (Text-Sprachsynthese) - VOICEVOX für Laravel](/de/packages/laravel-voicevox/client-talk.md)
- [Client-Modus: Song (Gesangs-Sprachsynthese) - VOICEVOX für Laravel](/de/packages/laravel-voicevox/client-song.md)
- [VOICEVOX für Laravel](/de/packages/laravel-voicevox/index.md)
