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

# De tap()-helper en de Tappable-trait

> Het gebruik en de implementatiepatronen van de tap()-helper van Laravel en de trait Illuminate\Support\Traits\Tappable.

## Wat is tap()?

`tap()` is een helper om "een waarde te gebruiken en diezelfde waarde ongewijzigd terug te geven". Je gebruikt hem wanneer je een bijeffect wilt tussenvoegen.

De implementatie in `Illuminate\Support\helpers.php` is eenvoudig.

```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) aanroepen"] --> B{"Is callback null?"}
    B -- ja --> C["HigherOrderTapProxy teruggeven"]
    B -- nee --> D["callback(value) uitvoeren"]
    D --> E["De oorspronkelijke value teruggeven"]
```

<Info>
  `tap()` negeert de returnwaarde van de callback. De returnwaarde is altijd de oorspronkelijke waarde.
</Info>

## Basisgebruik

Het meest basale gebruik is: een waarde ontvangen, verwerken en ongewijzigd teruggeven.

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

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

// $user wordt teruggegeven, ongeacht de returnwaarde van update()
```

Laat je de callback weg, dan krijg je een `HigherOrderTapProxy` terug, zodat je direct methodeaanroepen kunt doorketenen.

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

// Niet de returnwaarde van update() maar de oorspronkelijke User-instantie wordt teruggegeven
```

## Veelvoorkomende toepassingen

### Debugoutput tussenvoegen

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

### Logging of events invoegen midden in een keten

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

### Alleen een bijeffect uitvoeren zonder de returnwaarde te wijzigen

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

<Tip>
  Wil je de returnwaarde bewerken, gebruik dan `with()` of een gewone variabeletoewijzing. `tap()` blijft het leesbaarst als je hem beperkt tot bijeffecten.
</Tip>

## Wat is de Tappable-trait?

Door `Illuminate\Support\Traits\Tappable` te `use`n, voeg je een `tap()`-methode toe aan je klasse.

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

De trait biedt dus alleen een instantiemethode-versie van `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');
});
```

## Toepassing in packageontwikkeling

`Tappable` is handig wanneer je halverwege een fluent API een bijeffect wilt tussenvoegen. In combinatie met `Macroable` en `Conditionable` maak je een uitbreidbare builder in Laravel-stijl.

<Steps>
  <Step title="Maak een fluente klasse">
    ```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="Combineer Macroable, Conditionable en Tappable">
    ```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>

Gerelateerde pagina's:

* [Macroable-trait](/nl/advanced/macroable)
* [Conditionable-trait](/nl/advanced/conditionable)
* [VOICEVOX for Laravel](/nl/packages/laravel-voicevox) — een praktijkvoorbeeld waarin je `TalkAudioQuery` en `SongAudioQuery` met `tap()` bijstelt voordat je ze naar `generate()` stuurt

## Gebruiksvoorbeelden in de Laravel-core

Ook in Laravel zelf worden `tap()` / `Tappable` daadwerkelijk gebruikt.

* `Illuminate\Routing\Router` gebruikt `Macroable` en `Tappable` samen
* In `Router::respondWithRoute()` wordt `tap($route)->bind(...)` zonder callback gebruikt, zodat na het uitvoeren van `bind()` nog steeds de oorspronkelijke `$route` wordt teruggegeven
* In `Router::prepareResponse()` wordt na het converteren van de response met `tap(..., fn (...) => event(...))` een event afgevuurd
* In `Illuminate\Testing\Fluent\Concerns\Has` wordt assertie-ondersteuning geïmplementeerd met de keten `->tap(...)->first(...)->etc()`

```php theme={null}
// Uit 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>
  Op zichzelf is `tap()` een kleine helper, maar samen met `Macroable` en `Conditionable` bouw je er makkelijk de leesbare methodeketens mee die je vaak in Laravel ziet.
</Info>

## Volgende stappen

<Columns cols={2}>
  <Card title="Macroable-trait" icon="puzzle-piece" href="/nl/advanced/macroable">
    Leer het ontwerp waarmee je eigen methodes toevoegt aan bestaande klassen.
  </Card>

  <Card title="Conditionable-trait" icon="git-branch" href="/nl/advanced/conditionable">
    Leer conditionele ketens met `when()` / `unless()`.
  </Card>
</Columns>


## Related topics

- [Native modus: talk (tekst-naar-spraak) - VOICEVOX for Laravel](/nl/packages/laravel-voicevox/native-talk.md)
- [Clientmodus: song (zangsynthese) - VOICEVOX for Laravel](/nl/packages/laravel-voicevox/client-song.md)
- [Clientmodus: talk (tekst-naar-spraak) - VOICEVOX for Laravel](/nl/packages/laravel-voicevox/client-talk.md)
- [VOICEVOX for Laravel](/nl/packages/laravel-voicevox/index.md)
- [Een custom authenticatieguard implementeren](/nl/advanced/custom-auth-guard.md)
