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

# Lottery-Klasse

> Wie Sie mit Illuminate\Support\Lottery probabilistische Operationen elegant umsetzen. Inklusive Anwendungsfälle in der Paketentwicklung und der Fixierung für Tests.

## Was ist die Lottery-Klasse?

`Illuminate\Support\Lottery` ist eine Utility-Klasse, mit der Sie wahrscheinlichkeitsbasierte Operationen in einer Fluent API ausdrücken. Muster wie „nur jede 100. Anfrage ausführen" oder „nur bei einem Teil der Anfragen ausführliches Logging" lassen sich damit prägnant beschreiben.

<Info>
  Die Implementierung befindet sich in `src/Illuminate/Support/Lottery.php`. Laravel setzt diese Klasse selbst intern ein, etwa für Session-GC oder das Prunen abgelaufener Cache-Locks.
</Info>

```mermaid theme={null}
flowchart LR
  A["Lottery::odds(1, 100)"] --> B{"Zufällige Entscheidung"}
  B -->|"Gewinn (1%)"| C["winner-Callback ausführen"]
  B -->|"Niete (99%)"| D["loser-Callback ausführen"]
```

## Grundlegende Verwendung

### Wahrscheinlichkeit als Ganzzahl-Verhältnis

Mit `Lottery::odds($chances, $outOf)` geben Sie die Wahrscheinlichkeit als „$chances von $outOf Fällen" an.

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

Lottery::odds(1, 100)           // 1 von 100 Fällen
    ->winner(fn () => $this->runMaintenance())
    ->loser(fn () => null)
    ->choose();
```

### Wahrscheinlichkeit als Dezimalzahl

Wenn Sie `$outOf` weglassen und einen Dezimalwert zwischen `0.0` und `1.0` übergeben, wird dieser als Wahrscheinlichkeit verwendet.

```php theme={null}
Lottery::odds(0.01)             // 1 % Wahrscheinlichkeit
    ->winner(fn () => $this->sample())
    ->choose();
```

<Warning>
  Übersteigt der Dezimalwert `1.0`, wird eine `RuntimeException` geworfen.
</Warning>

### Boolean-Rückgabe ohne Callbacks

Ohne gesetzte winner-/loser-Callbacks liefert `choose()` `true` im Gewinnfall und `false` andernfalls.

```php theme={null}
$shouldSample = Lottery::odds(1, 50)->choose(); // bool
```

### Mehrmalige Ausführung

Übergeben Sie `choose($times)` eine Anzahl, wird ein Array mit den Ergebnissen zurückgegeben.

```php theme={null}
$results = Lottery::odds(1, 2)
    ->winner(fn () => 'win')
    ->loser(fn () => 'lose')
    ->choose(10);

// Beispiel: ['win', 'lose', 'win', 'win', 'lose', ...]
```

### Als Callable weitergeben

Da `Lottery` `__invoke` implementiert, können Sie eine Instanz direkt an APIs übergeben, die ein Callable erwarten.

```php theme={null}
// Beispiel: als zweites Argument von DB::whenQueryingForLongerThan
DB::whenQueryingForLongerThan(
    Interval::seconds(5),
    Lottery::odds(1, 5)->winner(function ($connection) {
        // Bei einer erkannten Slow Query 1/5 der Fälle einen Alert senden
        Alert::send("Slow query on {$connection->getName()}");
    })
);
```

## Praktische Anwendungsfälle

### 1. Cache Prunen (nur 1 von 100 Fällen)

Ideal für Wartungsaufgaben wie das Entfernen abgelaufener Einträge, die nicht bei jedem Aufruf laufen müssen.

```php theme={null}
Lottery::odds(1, 100)
    ->winner(fn () => Cache::store('database')->flush())
    ->choose();
```

### 2. Telemetrie-Sampling (Detail-Logs nur für einen Teil der Anfragen)

Wenn das Loggen jeder Anfrage zu teuer ist, eignet sich Sampling.

```php theme={null}
Lottery::odds(1, 20)
    ->winner(function () use ($request) {
        Log::channel('telemetry')->info('Request sampled', [
            'url'      => $request->url(),
            'duration' => microtime(true) - LARAVEL_START,
            'memory'   => memory_get_peak_usage(true),
        ]);
    })
    ->choose();
```

### 3. A/B-Test-artiges Verhalten

Nutzer werden probabilistisch auf zwei Code-Pfade verteilt.

```php theme={null}
$result = Lottery::odds(1, 2)
    ->winner(fn ($user) => $this->newCheckoutFlow($user))
    ->loser(fn ($user) => $this->legacyCheckoutFlow($user))
    ->choose();
```

### 4. Als Ergänzung zum Scheduler zufällige Tasks ausführen

Nützlich, wenn Sie einen Task zufällig ausführen wollen, ohne dass mehrere Server ihn doppelt starten.

```php theme={null}
// app/Console/Kernel.php
$schedule->call(function () {
    Lottery::odds(1, 3)
        ->winner(fn () => Artisan::call('cache:prune-stale-tags'))
        ->choose();
})->everyMinute();
```

## Probabilistische Muster im Laravel-Framework

Laravel selbst nutzt intern in vielen Fällen probabilistische Wartungsroutinen. Einige Implementierungen entstanden vor der Einführung der `Lottery`-Klasse und verwenden direkt `random_int()` — der Grundgedanke ist derselbe.

<Steps>
  <Step title="Session: Garbage Collection">
    `Illuminate\Session\Middleware\StartSession::configHitsLottery()` liest die Einstellung `lottery` aus `config/session.php` und entscheidet mit `random_int` über die GC-Ausführung.

    ```php theme={null}
    // config/session.php
    'lottery' => [2, 100], // 2 von 100 Anfragen

    // Intern in StartSession (nutzt direkt random_int)
    protected function configHitsLottery(array $config): bool
    {
        return random_int(1, $config['lottery'][1]) <= $config['lottery'][0];
    }
    ```
  </Step>

  <Step title="DatabaseLock: Prunen abgelaufener Locks">
    `Illuminate\Cache\DatabaseLock::acquire()` löscht bei jedem Lock-Erwerb nach demselben Verhältnis abgelaufene Locks.

    ```php theme={null}
    // config/cache.php (database-Treiber)
    'lock_lottery' => [2, 100], // 2 von 100 Fällen prunen

    // Intern in DatabaseLock::acquire() (nutzt direkt random_int)
    if (random_int(1, $this->lottery[1]) <= $this->lottery[0]) {
        $this->pruneExpiredLocks();
    }
    ```
  </Step>

  <Step title="DB::whenQueryingForLongerThan — Beispiel mit übergebener Lottery-Klasse">
    Da eine `Lottery`-Instanz als Callable verwendbar ist, lässt sie sich direkt als Slow-Query-Callback nutzen.

    ```php theme={null}
    DB::whenQueryingForLongerThan(
        Interval::seconds(5),
        Lottery::odds(1, 5)->winner(function ($connection) {
            Log::warning("Slow query on {$connection->getName()}");
        })
    );
    ```
  </Step>
</Steps>

<Tip>
  Während Session und DatabaseLock direkt `random_int()` nutzen, bietet die `Lottery`-Klasse den Vorteil, die Ergebnisse per `alwaysWin()`, `alwaysLose()` oder `fix()` für Tests zu steuern. In der Paketentwicklung erhöht die Wahl von `Lottery` die Testbarkeit.
</Tip>

## Verwendung in Tests

Für Tests von Code mit Zufall nutzen Sie die Test-API von `Lottery`.

### `Lottery::alwaysWin()` — immer gewinnen

```php theme={null}
public function test_maintenance_runs_on_win(): void
{
    $ranMaintenance = false;

    Lottery::alwaysWin(function () use (&$ranMaintenance) {
        Lottery::odds(1, 100)
            ->winner(function () use (&$ranMaintenance) {
                $ranMaintenance = true;
            })
            ->choose();
    });

    $this->assertTrue($ranMaintenance);
}
```

### `Lottery::alwaysLose()` — immer verlieren

```php theme={null}
public function test_maintenance_skipped_on_lose(): void
{
    $ranMaintenance = false;

    Lottery::alwaysLose(function () use (&$ranMaintenance) {
        Lottery::odds(1, 100)
            ->winner(function () use (&$ranMaintenance) {
                $ranMaintenance = true;
            })
            ->choose();
    });

    $this->assertFalse($ranMaintenance);
}
```

### `Lottery::fix()` — Ergebnisse als Sequenz festlegen

Sie können die Ergebnisse mehrerer Aufrufe als Array aus `true`/`false` steuern.

```php theme={null}
public function test_alternating_results(): void
{
    Lottery::fix([true, false, true, false]);

    $results = Lottery::odds(1, 100)
        ->winner(fn () => 'winner')
        ->loser(fn () => 'loser')
        ->choose(4);

    $this->assertSame(['winner', 'loser', 'winner', 'loser'], $results);

    Lottery::determineResultNormally(); // Nach dem Test unbedingt zurücksetzen
}
```

<Warning>
  `alwaysWin()`, `alwaysLose()` und `fix()` verändern globale statische Eigenschaften. Rufen Sie in `tearDown()` unbedingt `Lottery::determineResultNormally()` auf.
</Warning>

```php theme={null}
protected function tearDown(): void
{
    Lottery::determineResultNormally();

    parent::tearDown();
}
```

### `Lottery::setResultFactory()` — eigene Factory injizieren

Für feinere Kontrolle nutzen Sie eine eigene Factory.

```php theme={null}
Lottery::setResultFactory(function ($chances, $outOf) {
    // Eigene Logik, die immer gewinnt
    return true;
});

// Nach dem Test zurücksetzen
Lottery::determineResultNormally();
```

## Einsatz in der Paketentwicklung

### Registrierung im Service Provider

Wenn Sie Wartungsroutinen in den Service Provider Ihres Pakets einbauen, verteilen Sie mit `Lottery` die Last.

```php theme={null}
use Illuminate\Support\Lottery;
use Illuminate\Support\ServiceProvider;

class AcmeServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        $this->app->booted(function () {
            Lottery::odds(1, 100)
                ->winner(fn () => $this->pruneExpiredRecords())
                ->choose();
        });
    }

    protected function pruneExpiredRecords(): void
    {
        $this->app['db']->table('acme_logs')
            ->where('expires_at', '<', now())
            ->delete();
    }
}
```

### Wahrscheinlichkeit aus der Konfiguration lesen

Machen Sie die Wahrscheinlichkeit über eine Config-Datei änderbar, damit Nutzer sie leichter anpassen können.

```php theme={null}
$lottery = config('acme.prune_lottery', [1, 100]);

Lottery::odds(...$lottery)
    ->winner(fn () => $this->pruneExpiredRecords())
    ->choose();
```

```php theme={null}
// config/acme.php
return [
    // [Gewinne, Versuche] = 1 von 100 Anfragen prunen
    'prune_lottery' => [1, 100],
];
```

### Sampling in einer Middleware

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

class SampleTelemetryMiddleware
{
    public function handle(Request $request, Closure $next): Response
    {
        $response = $next($request);

        Lottery::odds(1, 50)
            ->winner(fn () => $this->recordTelemetry($request, $response))
            ->choose();

        return $response;
    }
}
```

## API-Referenz

| Methode                               | Beschreibung                                                 |
| ------------------------------------- | ------------------------------------------------------------ |
| `Lottery::odds($chances, $outOf)`     | Statische Factory, erzeugt eine Lottery-Instanz              |
| `->winner(callable $callback)`        | Callback im Gewinnfall setzen                                |
| `->loser(callable $callback)`         | Callback im Verlustfall setzen                               |
| `->choose($times = null)`             | Lottery ausführen; mit `$times` wird ein Array zurückgegeben |
| `Lottery::alwaysWin($callback)`       | Für Tests: immer gewinnen                                    |
| `Lottery::alwaysLose($callback)`      | Für Tests: immer verlieren                                   |
| `Lottery::fix($sequence)`             | Für Tests: Ergebnisse als Sequenz fixieren                   |
| `Lottery::determineResultNormally()`  | Testfixierung zurücksetzen                                   |
| `Lottery::setResultFactory(callable)` | Eigene Entscheidungslogik injizieren                         |

## Verwandte Seiten

<Columns cols={2}>
  <Card title="Macroable-Trait" icon="puzzle-piece" href="/de/advanced/macroable">
    Lernen Sie das Erweiterungsmuster kennen, um bestehenden Klassen neue Methoden hinzuzufügen.
  </Card>

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


## Related topics

- [Fluent-Klasse](/de/advanced/fluent.md)
- [String-Operationen (Str-Klasse)](/de/strings.md)
- [E-Mail-Versand](/de/mail.md)
- [Eigene Casts in Eloquent](/de/advanced/eloquent-casts.md)
- [Feed Generator](/de/packages/laravel-bluesky/feed-generator.md)
