Skip to main content
Per rendere un pacchetto utilizzabile non solo nelle normali richieste HTTP, ma anche con Octane e con i queue worker, devi decidere per quanto tempo e che cosa può conservare ciascun servizio. Se salvi dati specifici di una richiesta in un singleton, un’elaborazione diversa potrebbe leggere dati obsoleti. Questa pagina esamina l’implementazione del container e del queue worker di Laravel Framework v13.36.0, oltre a quella di Octane, e collega i metodi di registrazione di base del service container alla manutenzione a lungo termine di un pacchetto. Scegliere scoped() non basta a reimpostare tutti i riferimenti tra oggetti e tutto lo stato statico.

Scegliere il metodo di registrazione in base alla durata del servizio

Questa tabella confronta le risoluzioni normali. I percorsi speciali, come la risoluzione con parametri espliciti o il contextual binding, vanno verificati separatamente. Anche con bind(), se salvi il servizio ottenuto in una proprietà di un altro singleton, quel riferimento rimane. Il metodo di registrazione è una regola di creazione e riutilizzo del container, non una regola che obbliga a ricreare gli oggetti conservati da chi li usa.

scoped combina una registrazione condivisa con il tracciamento delle istanze da rimuovere

Il metodo Container::scoped() esaminato esegue due operazioni.
  1. Registra la chiave in scopedInstances.
  2. Chiama singleton() e la registra come binding condiviso.
L’istanza stessa viene salvata nello stesso instances usato dai singleton. forgetScopedInstances() esegue unset() sulle istanze salvate per le chiavi registrate. La logica di creazione del binding rimane, quindi la successiva risoluzione normale può creare un nuovo oggetto. Questa operazione non reimposta le proprietà del vecchio oggetto e non riscrive i riferimenti conservati da altri oggetti. Un vecchio oggetto ancora referenziato può continuare a essere usato.

Il confine lo crea l’ambiente di esecuzione

Il container non monitora da solo l’inizio delle richieste HTTP o dei job.
  • Queue worker: QueueServiceProvider passa al Worker una callback che reimposta lo scope. Worker::daemon() la invoca nel ciclo prima di prelevare il job successivo e, all’interno della callback, esegue forgetScopedInstances() e la pulizia delle istanze risolte dalle Facade, tra le altre cose.
  • Octane: la configurazione predefinita ufficiale registra FlushTemporaryContainerInstances su OperationTerminated. Questo listener chiama forgetScopedInstances().
  • Comandi residenti o cicli personalizzati: ripetere semplicemente make() non crea un confine. Il ciclo di vita deve essere progettato dall’infrastruttura di esecuzione.
Non chiamare forgetScopedInstances() di tua iniziativa dalla normale logica applicativa o dal boot() di un pacchetto. Influisce su tutti i servizi scoped del container. Inoltre, non tutti i percorsi di esecuzione dei job, compresa l’esecuzione sincrona, passano necessariamente per lo stesso percorso di reset del Worker residente.

Rendere scoped lo stato condiviso all’interno di un’elaborazione

Considera un pacchetto di spedizioni che vuole condividere l’identificativo della destinazione all’interno di una singola richiesta o di un singolo job. Invece di conservare direttamente la Request HTTP, salva solo il valore necessario.
Nel service provider del pacchetto, registra un context vuoto senza leggere lo stato dell’utente al momento della creazione.
Nel controller o nel handle() del job dell’applicazione che usa il pacchetto, imposta un identificativo per cui sono già stati completati la validazione dell’input e il controllo dei permessi. Gli altri servizi che risolvono questo tipo nello stesso ciclo di vita possono fare riferimento allo stesso context.
Questo context non è un meccanismo di autorizzazione. Poter impostare un identificativo è diverso dall’essere autorizzati ad accedere a quella destinazione. Inoltre, scoped() non è una forma di persistenza su database o cache esterna. I valori da passare al job successivo vanno passati esplicitamente come dati del job.
Con Octane, register() e boot() dei service provider vengono eseguiti all’avvio iniziale del worker. Non progettare il codice in modo da salvare nel context l’utente o la destinazione correnti in boot(). I valori specifici di ogni elaborazione vanno impostati dopo l’inizio dell’elaborazione.

I riferimenti da un singleton a un servizio scoped non vengono aggiornati automaticamente

Con la registrazione seguente, rendere scoped solo il context non produce il comportamento atteso.
Se DeliveryService salva il context in una proprietà nel costruttore, continua a conservare il primo context creato. Anche se il container rimuove il context salvato, la proprietà del DeliveryService già creato non cambia. Scegli la soluzione in base alla responsabilità del servizio.
  1. Passare i valori necessari a ogni elaborazione come argomenti dei metodi. Se non serve condividere stato, è la soluzione più semplice.
  2. Rendere scoped anche il servizio che conserva il riferimento. Sia DeliveryService sia il context vengono ricreati per ogni elaborazione.
  3. Passare un resolver che risolve al momento dell’uso. Se devi mantenere il singleton, recupera ogni volta il servizio necessario dal container corrente.
Nel terzo esempio, invece di catturare il vecchio context in una closure, lo si risolve al momento della chiamata.
In questo esempio DeliveryService deve ricevere una Closure nel costruttore ed essere modificato in un’API che la invoca a ogni operazione. Invocare il resolver una sola volta nel costruttore e salvarne il risultato non risolve il problema. Si tratta di un esempio di progettazione che applica il container resolver della documentazione ufficiale di Octane a un context specifico del pacchetto.

Verificare anche lo stato che scoped non rimuove

scoped() non rimuove automaticamente lo stato seguente.
  • Valori aggiunti a proprietà statiche proprie del pacchetto
  • Riferimenti al context salvati in un altro singleton o in variabili globali
  • “Utente corrente” o “destinazione corrente” conservati all’interno di un singleton
  • Riferimenti conservati da Facade o livelli di cache personalizzati
Distingui il reset effettuato dall’infrastruttura di esecuzione standard dal reset dello stato proprio del pacchetto. Ridurre i punti in cui si conserva lo stato specifico di ogni elaborazione è più semplice che mantenere una logica di pulizia personalizzata per ogni ambiente di esecuzione.

Scrivere test che attraversano un confine nello stesso container

Se i test HTTP si limitano a creare ogni volta una nuova applicazione, possono sfuggire i problemi dovuti al riutilizzo dello stesso container in un processo residente. Per prima cosa, verifica con il solo container la condivisione all’interno della stessa elaborazione e la ricreazione dopo il confine. I test seguenti sono in formato PHPUnit. Il primo test, come i test ufficiali del Container, usa forgetScopedInstances() per verificare l’effetto del confine senza avviare l’intero Worker.
Il secondo test documenta il comportamento per cui il riferimento rimane. Nel pacchetto reale aggiungi anche test che verificano che la soluzione adottata usi un nuovo context o un nuovo valore. I test del solo container non verificano la sandbox di Octane né il percorso di esecuzione reale del queue worker. Servono anche test di integrazione che eseguano elaborazioni consecutive negli ambienti di esecuzione che dichiari di supportare. Nei deploy che modificano il metodo di registrazione o l’implementazione dei servizi, ricarica i processi residenti per applicare il nuovo codice.

Pagine correlate

Hook di risoluzione dei servizi nei pacchetti

Approfondisce afterResolving, il recupero delle istanze condivise e le differenze di configurazione alla nuova risoluzione.

Laravel Octane

Approfondisce la conservazione della Request e del container e le avvertenze operative sui processi residenti.

Fonti primarie consultate

Ultima modifica il 14 ottobre 2026