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

# Service provider differiti

> Come implementare il caricamento differito dei servizi implementando l'interfaccia DeferrableProvider. Una funzione poco appariscente ma cruciale per ottimizzare le performance dei pacchetti.

I service provider registrati all'avvio di Laravel vengono caricati a ogni richiesta, anche se le loro funzionalità non vengono mai usate. I deferred service provider risolvono questo problema: rinviano il caricamento finché il servizio non viene effettivamente richiesto.

<Info>
  Questa pagina presuppone la conoscenza delle [basi dello sviluppo di pacchetti](/it/advanced/package-development). Ti consigliamo di leggere prima le nozioni di base sui service provider.
</Info>

## Perché servono i deferred provider

I service provider normali chiamano `register()` e `boot()` a ogni richiesta. Inizializzare ogni volta funzionalità che non vengono usate in tutte le pagine — come invio email, code o cache — è uno spreco.

```php theme={null}
// register() di questo provider viene chiamato a ogni richiesta
class ReportServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        // ogni volta bindiamo un pesante servizio di report
        $this->app->singleton(ReportGenerator::class, function ($app) {
            return new ReportGenerator(
                $app->make(PdfRenderer::class),
                $app->make(ChartRenderer::class),
                $app->make(DataExporter::class),
            );
        });
    }
}
```

Rendendolo differito, verrà inizializzato solo nelle richieste che generano realmente un report.

***

## L'interfaccia DeferrableProvider

`Illuminate\Contracts\Support\DeferrableProvider` è un'interfaccia semplice con un solo metodo: `provides()`.

```php theme={null}
namespace Illuminate\Contracts\Support;

interface DeferrableProvider
{
    public function provides();
}
```

Basta implementarla e il provider passa in modalità differita.

***

## Implementazione di base

L'implementazione di un deferred provider si articola in tre passi.

<Steps>
  <Step title="Implementare DeferrableProvider">
    ```php theme={null}
    use Illuminate\Contracts\Support\DeferrableProvider;
    use Illuminate\Support\ServiceProvider;

    class ReportServiceProvider extends ServiceProvider implements DeferrableProvider
    {
        // ...
    }
    ```
  </Step>

  <Step title="Registrare i servizi in register()">
    Come in un provider normale, i bind vanno in `register()`.

    ```php theme={null}
    public function register(): void
    {
        $this->app->singleton(ReportGenerator::class, function ($app) {
            return new ReportGenerator(
                $app->make(PdfRenderer::class),
                $app->make(ChartRenderer::class),
                $app->make(DataExporter::class),
            );
        });

        $this->app->singleton(ReportRepository::class, function ($app) {
            return new ReportRepository($app->make('db'));
        });
    }
    ```
  </Step>

  <Step title="Restituire i servizi registrati da provides()">
    `provides()` deve restituire **tutti i servizi** registrati in `register()`. Da questa lista Laravel decide "quando richiedere quale servizio caricare questo provider".

    ```php theme={null}
    public function provides(): array
    {
        return [
            ReportGenerator::class,
            ReportRepository::class,
        ];
    }
    ```
  </Step>
</Steps>

***

## Meccanismo del service manifest

All'avvio Laravel genera un file manifest chiamato `bootstrap/cache/services.php`. In esso è memorizzata la lista dei servizi forniti dai deferred provider.

```php theme={null}
// esempio (autogenerato) di bootstrap/cache/services.php
return [
    'providers' => [
        // stessa lista di bootstrap/providers.php
    ],
    'eager' => [
        // provider a caricamento immediato
        App\Providers\AppServiceProvider::class,
    ],
    'deferred' => [
        // mapping nome-servizio => classe provider
        'App\Services\ReportGenerator' => ReportServiceProvider::class,
        'App\Repositories\ReportRepository' => ReportServiceProvider::class,
        'cache'     => Illuminate\Cache\CacheServiceProvider::class,
        'cache.store' => Illuminate\Cache\CacheServiceProvider::class,
        'queue'     => Illuminate\Queue\QueueServiceProvider::class,
    ],
    'when' => [],
];
```

Grazie a questo manifest, Laravel sa "quale provider fornisce quale servizio" senza dover caricare i file. I provider vengono caricati solo alla prima risoluzione del servizio.

<Tip>
  Se aggiungi o modifichi provider, rigenera il manifest.

  ```shell theme={null}
  php artisan optimize:clear
  # oppure
  php artisan clear-compiled
  ```
</Tip>

### Flusso del funzionamento interno

```mermaid theme={null}
sequenceDiagram
    participant App as App<br>Laravel
    participant Container as Service<br>container
    participant Manifest as Manifest<br>services.php
    participant Provider as ReportService<br>Provider

    App->>Manifest: All'avvio legge il manifest
    Manifest-->>App: Restituisce l'elenco dei servizi deferred
    Note over App: A questo punto il provider non è stato caricato

    App->>Container: $app->make(ReportGenerator::class)
    Container->>Manifest: È un servizio deferred?
    Manifest-->>Container: Sì, lo fornisce ReportServiceProvider
    Container->>Provider: Chiama register() + boot()
    Provider-->>Container: Registra i binding
    Container-->>App: Restituisce l'istanza di ReportGenerator
```

***

## Importanza del metodo provides()

Se in `provides()` manca una registrazione, quel servizio non verrà mai risolto.

```php theme={null}
public function register(): void
{
    $this->app->singleton(ReportGenerator::class, fn ($app) => new ReportGenerator());

    // binding aggiunto
    $this->app->singleton('report', fn ($app) => $app->make(ReportGenerator::class));
}

public function provides(): array
{
    return [
        ReportGenerator::class,
        'report',  // ← non dimenticare le chiavi stringa
    ];
}
```

Lo stesso vale per le proprietà `$bindings` / `$singletons`: vanno anch'esse elencate in `provides()`.

```php theme={null}
class AnalyticsServiceProvider extends ServiceProvider implements DeferrableProvider
{
    public $singletons = [
        AnalyticsClient::class => DefaultAnalyticsClient::class,
    ];

    public function provides(): array
    {
        // restituisci tutte le chiavi elencate in $singletons
        return [
            AnalyticsClient::class,
        ];
    }
}
```

***

## Limitazioni dei deferred provider

I deferred provider sono adatti quando l'unico scopo è **registrare binding nel container**. Non si può differire un provider che in `boot()` fa cose come queste.

| Limitazione                                            | Motivo                                                                        |
| ------------------------------------------------------ | ----------------------------------------------------------------------------- |
| Registrazione di rotte                                 | Le rotte vengono risolte all'avvio dell'app, quindi il deferring non funziona |
| Registrazione di middleware globali                    | La registrazione serve prima dell'elaborazione della richiesta                |
| Registrazione di listener di eventi (sempre necessari) | Se non è registrato prima che l'evento venga emesso, non funziona             |
| Aggiunta di direttive Blade                            | La registrazione serve prima della compilazione delle view                    |

<Warning>
  Puoi scrivere il metodo `boot()` in un deferred provider, ma il suo contenuto non verrà eseguito finché il servizio non viene risolto. Mettere in `boot()` operazioni "sempre necessarie" come rotte e middleware porta a comportamenti imprevisti.
</Warning>

***

## Metodo when() — registrazione via trigger evento

Con il metodo `when()` puoi registrare il provider al verificarsi di eventi specifici. Utile per provider necessari solo in contesti specifici, come l'elaborazione dei job.

```php theme={null}
class ReportServiceProvider extends ServiceProvider implements DeferrableProvider
{
    public function register(): void
    {
        $this->app->singleton(ReportGenerator::class, fn () => new ReportGenerator());
    }

    public function provides(): array
    {
        return [ReportGenerator::class];
    }

    /**
     * Carica il provider anche quando l'evento indicato viene emesso,
     * indipendentemente dalla risoluzione dei binding.
     */
    public function when(): array
    {
        return [
            \App\Events\ReportRequested::class,
        ];
    }
}
```

Se l'evento restituito da `when()` viene emesso, il provider viene caricato anche se il servizio non è stato risolto direttamente.

***

## Utilizzo nello sviluppo di pacchetti

Anche nella distribuzione come pacchetto di terze parti, i deferred provider contribuiscono alle performance dell'applicazione dell'utente.

### Pattern consigliato

```php theme={null}
namespace Acme\Analytics;

use Illuminate\Contracts\Support\DeferrableProvider;
use Illuminate\Support\ServiceProvider;

class AnalyticsServiceProvider extends ServiceProvider implements DeferrableProvider
{
    public function register(): void
    {
        $this->mergeConfigFrom(__DIR__.'/../config/analytics.php', 'analytics');

        $this->app->singleton(AnalyticsManager::class, function ($app) {
            return new AnalyticsManager($app->make('config')->get('analytics'));
        });

        $this->app->singleton('analytics', fn ($app) => $app->make(AnalyticsManager::class));
    }

    public function boot(): void
    {
        // usa boot() solo per la registrazione della pubblicazione
        if ($this->app->runningInConsole()) {
            $this->publishes([
                __DIR__.'/../config/analytics.php' => config_path('analytics.php'),
            ], 'analytics-config');
        }
    }

    public function provides(): array
    {
        return [
            AnalyticsManager::class,
            'analytics',
        ];
    }
}
```

<Info>
  `mergeConfigFrom()` verifica internamente se la configurazione è in cache, quindi può essere chiamato in sicurezza dentro `register()` di un deferred provider. Se la configurazione è già in cache, non fa nulla.
</Info>

### Isolare la registrazione dei comandi Artisan con `runningInConsole()`

La registrazione dei comandi serve solo all'avvio di Artisan, quindi usa un branch con `runningInConsole()`. Se il provider che fornisce i comandi è differito, ricorda di includere le classi dei comandi in `provides()` oppure predisponi un provider dedicato ai soli comandi.

```php theme={null}
public function boot(): void
{
    if ($this->app->runningInConsole()) {
        $this->commands([
            AnalyticsFlushCommand::class,
        ]);
    }
}
```

***

## Esempi nel core di Laravel

Molti dei provider core di Laravel sono differiti. Il design è pensato per evitare di caricare in modo immediato tutti i servizi che non vengono usati a ogni richiesta.

| Provider                     | Servizi forniti                         |
| ---------------------------- | --------------------------------------- |
| `CacheServiceProvider`       | `cache`, `cache.store`, `RateLimiter`   |
| `QueueServiceProvider`       | `queue`, `queue.worker`, `queue.failer` |
| `MailServiceProvider`        | `mail.manager`, `mailer`                |
| `RedisServiceProvider`       | `redis`, `redis.connection`             |
| `HashServiceProvider`        | `hash`, `hash.driver`                   |
| `ValidationServiceProvider`  | `validator`, `validation.presence`      |
| `TranslationServiceProvider` | `translator`                            |
| `BroadcastServiceProvider`   | `Broadcast`                             |

In un'applicazione fatta solo di endpoint API può capitare che `MailServiceProvider` o `BroadcastServiceProvider` non vengano mai caricati durante una richiesta.

***

## Criteri per decidere se differire

<AccordionGroup>
  <Accordion title="Servizi adatti al deferring">
    * Servizi non usati in tutte le richieste (mail, report, client di API esterne, ecc.)
    * Servizi la cui inizializzazione richiede connessioni esterne o letture di file
    * Servizi con grafi di oggetti pesanti
    * Provider che offrono comandi usati solo da CLI
  </Accordion>

  <Accordion title="Servizi NON adatti al deferring">
    * Provider che registrano rotte (con `loadRoutesFrom`, ecc.)
    * Provider che registrano middleware o exception handler sempre attivi
    * Provider che registrano global scope o observer Eloquent
    * Servizi leggeri usati nella maggior parte delle richieste (l'overhead del deferring sarebbe maggiore)
  </Accordion>
</AccordionGroup>

***

## Pagine correlate

<Columns cols={2}>
  <Card title="Nozioni di sviluppo dei pacchetti" icon="box" href="/it/advanced/package-development">
    Come sviluppare pacchetti Laravel imperniati sui service provider.
  </Card>

  <Card title="Gestire la compatibilità tra versioni dei pacchetti" icon="layers" href="/it/advanced/package-versioning">
    Strategie di manutenzione dei pacchetti per gli upgrade major di Laravel e PHP.
  </Card>
</Columns>


## Related topics

- [Service provider](/it/service-providers.md)
- [FAQ sulla nuova struttura dell'app da Laravel 11](/it/advanced/app-structure-faq.md)
- [Ciclo di vita della richiesta](/it/lifecycle.md)
- [Aggiornamento da Laravel 10 a 11](/it/blog/upgrade-10-to-11.md)
- [Struttura dell'applicazione da Laravel 11](/it/advanced/app-structure.md)
