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

# Classe Lottery

> Come implementare in modo elegante operazioni probabilistiche con Illuminate\Support\Lottery. Include casi d'uso per lo sviluppo di pacchetti e il fissaggio dei risultati nei test.

## Cos'è la classe Lottery

`Illuminate\Support\Lottery` è una classe di utilità che esprime operazioni basate sulla probabilità con un'API fluent. Permette di scrivere in modo semplice pattern come "esegui un'elaborazione una volta ogni 100 richieste" o "registra i log dettagliati solo per una parte delle richieste".

<Info>
  L'implementazione si trova in `src/Illuminate/Support/Lottery.php`. Laravel usa questa classe internamente per la GC delle sessioni, la pulizia dei lock di cache e altro.
</Info>

```mermaid theme={null}
flowchart LR
  A["Lottery::odds(1, 100)"] --> B{"Estrazione casuale"}
  B -->|"Vincita (1%)"| C["Esegue il callback winner"]
  B -->|"Perdita (99%)"| D["Esegue il callback loser"]
```

## Uso di base

### Indicare la probabilità come rapporto intero

Con `Lottery::odds($chances, $outOf)` indichi la probabilità "$chances vincite su $outOf tentativi".

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

Lottery::odds(1, 100)           // 1 volta su 100
    ->winner(fn () => $this->runMaintenance())
    ->loser(fn () => null)
    ->choose();
```

### Indicare la probabilità come decimale

Omettendo `$outOf` e passando un decimale tra `0.0` e `1.0`, il valore viene usato direttamente come probabilità.

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

<Warning>
  Nella forma decimale, se il valore supera `1.0` viene sollevata una `RuntimeException`.
</Warning>

### Restituire un booleano senza callback

Se non imposti winner / loser, `choose()` restituisce `true` in caso di vincita e `false` in caso di perdita.

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

### Eseguire più volte

Passando il numero di ripetizioni a `choose($times)` ottieni un array di risultati.

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

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

### Passarlo come callable

L'istanza `Lottery` implementa `__invoke`, quindi la puoi passare direttamente alle API che accettano un callable.

```php theme={null}
// esempio: la passi come secondo argomento di DB::whenQueryingForLongerThan
DB::whenQueryingForLongerThan(
    Interval::seconds(5),
    Lottery::odds(1, 5)->winner(function ($connection) {
        // quando viene rilevata una query lenta, invia un alert con probabilità 1/5
        Alert::send("Slow query on {$connection->getName()}");
    })
);
```

## Casi d'uso pratici

### 1. Prune della cache (eseguito 1 volta su 100)

Ideale per operazioni di manutenzione che non è necessario eseguire sempre, come la rimozione dei record scaduti.

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

### 2. Sampling telemetrico (log dettagliati solo su una parte delle richieste)

Se registrare a log tutte le richieste è troppo costoso, puoi usarlo per il 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. Comportamento tipo A/B test

Distribuisci probabilisticamente gli utenti su due percorsi di codice.

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

### 4. Esecuzione randomizzata di task periodici a supporto dello scheduler

Utile quando vuoi eseguire un task in modo casuale su più server evitando esecuzioni duplicate.

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

## Pattern probabilistici nel framework Laravel

Laravel usa ampiamente pattern probabilistici anche internamente per operazioni di manutenzione. Alcune implementazioni, scritte prima dell'introduzione della classe `Lottery`, usano direttamente `random_int()`, ma seguono la stessa idea.

<Steps>
  <Step title="Session: garbage collection">
    `Illuminate\Session\Middleware\StartSession::configHitsLottery()` usa l'impostazione `lottery` di `config/session.php` ed esegue la GC verificando la probabilità con `random_int`.

    ```php theme={null}
    // config/session.php
    'lottery' => [2, 100], // 2 volte ogni 100 richieste

    // interno di StartSession (usa direttamente random_int)
    protected function configHitsLottery(array $config): bool
    {
        return random_int(1, $config['lottery'][1]) <= $config['lottery'][0];
    }
    ```
  </Step>

  <Step title="DatabaseLock: prune dei lock scaduti">
    `Illuminate\Cache\DatabaseLock::acquire()` a ogni acquisizione applica lo stesso pattern probabilistico per rimuovere i lock scaduti.

    ```php theme={null}
    // config/cache.php (driver database)
    'lock_lottery' => [2, 100], // esegue il prune 2 volte su 100

    // interno di DatabaseLock::acquire() (usa direttamente random_int)
    if (random_int(1, $this->lottery[1]) <= $this->lottery[0]) {
        $this->pruneExpiredLocks();
    }
    ```
  </Step>

  <Step title="DB::whenQueryingForLongerThan — passare un'istanza Lottery">
    Poiché un'istanza `Lottery` è callable, puoi usarla direttamente come callback di rilevamento delle query lente.

    ```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>
  Session e DatabaseLock usano direttamente `random_int()`, mentre la classe `Lottery` ti permette di controllare il risultato nei test con `alwaysWin()` / `alwaysLose()` / `fix()`. Nello sviluppo di pacchetti la scelta di `Lottery` migliora la testabilità.
</Tip>

## Utilizzo nei test

Per testare codice che dipende dalla casualità usa le API di test fornite da `Lottery`.

### `Lottery::alwaysWin()` — vinci sempre

```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()` — perdi sempre

```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()` — fissare il risultato con una sequenza

Puoi controllare l'esito di più chiamate con un array di `true`/`false`.

```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(); // dopo il test ripristina sempre
}
```

<Warning>
  `alwaysWin()` / `alwaysLose()` / `fix()` modificano proprietà statiche globali. Chiama sempre `Lottery::determineResultNormally()` nel `tearDown()` del test.
</Warning>

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

    parent::tearDown();
}
```

### `Lottery::setResultFactory()` — iniettare una factory personalizzata

Se serve un controllo più fine usa una factory personalizzata.

```php theme={null}
Lottery::setResultFactory(function ($chances, $outOf) {
    // logica personalizzata che vince sempre
    return true;
});

// dopo il test resetta
Lottery::determineResultNormally();
```

## Utilizzo nello sviluppo di pacchetti

### Registrazione nel service provider

Quando integri elaborazioni di manutenzione nel service provider di un pacchetto, usa `Lottery` per distribuire il carico.

```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();
    }
}
```

### Leggere gli odds dalla configurazione

Rendendo la probabilità modificabile dal file di configurazione, gli utenti possono regolarla facilmente.

```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 [
    // [vincite, tentativi] = 1 prune ogni 100 richieste
    'prune_lottery' => [1, 100],
];
```

### Sampling nel 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 reference

| Metodo                                | Descrizione                                                 |
| ------------------------------------- | ----------------------------------------------------------- |
| `Lottery::odds($chances, $outOf)`     | Factory statica che crea un'istanza Lottery                 |
| `->winner(callable $callback)`        | Imposta il callback in caso di vincita                      |
| `->loser(callable $callback)`         | Imposta il callback in caso di perdita                      |
| `->choose($times = null)`             | Esegue la lottery. Se indichi `$times` restituisce un array |
| `Lottery::alwaysWin($callback)`       | Per test: vinci sempre                                      |
| `Lottery::alwaysLose($callback)`      | Per test: perdi sempre                                      |
| `Lottery::fix($sequence)`             | Per test: fissa i risultati come sequenza                   |
| `Lottery::determineResultNormally()`  | Reset del fissaggio per test                                |
| `Lottery::setResultFactory(callable)` | Inietta una logica di estrazione personalizzata             |

## Pagine correlate

<Columns cols={2}>
  <Card title="Trait Macroable" icon="puzzle-piece" href="/it/advanced/macroable">
    Impara il pattern di estensione per aggiungere metodi a classi esistenti.
  </Card>

  <Card title="Trait Conditionable" icon="git-branch" href="/it/advanced/conditionable">
    Impara a progettare catene condizionali con `when()` / `unless()`.
  </Card>
</Columns>


## Related topics

- [Classe Fluent](/it/advanced/fluent.md)
- [Manipolazione delle stringhe (classe Str)](/it/strings.md)
- [Laravel Pennant](/it/pennant.md)
- [Cast personalizzati di Eloquent](/it/advanced/eloquent-casts.md)
- [Regole di validazione personalizzate](/it/advanced/custom-validation-rules.md)
