Skip to main content
Quando un pacchetto aggiunge funzionalità a un servizio di Laravel, può essere utile non creare l’istanza finché non viene usata e, allo stesso tempo, applicare la configurazione anche se l’istanza è già stata creata. Il metodo protected callAfterResolving() del service provider serve proprio a combinare questi due comportamenti. Questa pagina esamina l’implementazione di Laravel Framework v13.35.0 e approfondisce l’estensione da boot() descritta in Sviluppo di pacchetti Laravel. Non si tratta di un hook che attende il completamento dell’avvio dell’intera applicazione, ma di un hook sulla risoluzione di un servizio specifico.

Attendere se non risolto, eseguire subito se già risolto

ServiceProvider::callAfterResolving() esegue due passaggi.
  1. Registra la callback in afterResolving() del container.
  2. Se resolved() è true, ottiene il servizio con make() e invoca la callback anche immediatamente.
Se il servizio non è ancora stato risolto, il metodo stesso non esegue make() sul servizio. In una risoluzione normale, il container costruisce l’oggetto, applica gli extender, invoca le callback resolving e infine le callback afterResolving. Nel normale recupero di un singleton, il container restituisce anticipatamente l’istanza salvata, quindi afterResolving non viene attivato a ogni recupero. Il punto importante è che registrando semplicemente afterResolving() si perde la configurazione dei singleton creati prima della registrazione.

Aggiungere una regola alla Factory di validazione

Come esempio di un pacchetto che fornisce una propria regola per stringhe, registriamo la regola dopo la risoluzione di validator. Il ValidationServiceProvider ufficiale registra questa chiave come singleton e il provider stesso supporta il caricamento differito.
Nell’applicazione che utilizza il pacchetto, la regola si combina con le regole normali.
In questo esempio extend() è l’API di registrazione delle regole di Illuminate\Validation\Factory, ed è un metodo diverso dall’extend() del container descritto più avanti. Poiché le normali regole personalizzate possono non essere eseguite con valori vuoti, l’obbligatorietà va indicata con required. Per la progettazione dettagliata delle regole, consulta Regole di validazione personalizzate. Factory::extend() sovrascrive l’elemento dell’array con lo stesso nome di regola, quindi registrare di nuovo la stessa logica, come in questo esempio, non aggiunge voci. Tuttavia, per non sovrascrivere le regole di altri pacchetti, aggiungi un prefisso specifico del pacchetto ai nomi delle regole che esponi.
La callback viene eseguita quando la Factory viene risolta. La closure di verifica della regola viene eseguita più tardi, quando il Validator valida il valore. La registrazione dell’hook non valida alcun input.

Allineare la chiave di destinazione e il controllo di risoluzione

Negli eventi di risoluzione normali del container, vengono selezionate non solo le callback che corrispondono alla chiave registrata, ma anche quelle che corrispondono al tipo dell’oggetto ottenuto. Invece, resolved($name), usato immediatamente da callAfterResolving(), verifica se per la chiave normalizzata rispetto agli alias esiste un flag di risoluzione o un’istanza salvata. Non effettua una ricerca su tutti gli oggetti già creati. Per questo, il fatto che un’interfaccia o una classe sia già stata risolta non garantisce che resolved() restituisca true anche per un’altra chiave. Verifica il binding e gli alias effettivi del servizio di destinazione e testa anche il caso già risolto con la stessa chiave. Nell’esempio precedente si specifica validator, registrato dal provider ufficiale. Inoltre, resolved() include anche il caso “risolto in passato”. Non significa che l’istanza corrente sia necessariamente ancora presente.

Non è un’API che garantisce un’esecuzione “una sola volta”

callAfterResolving() lascia la callback registrata. Anche dopo l’esecuzione immediata, la callback registrata verrà eseguita ogni volta che l’oggetto viene risolto di nuovo in futuro. Inoltre, chiamando di nuovo il metodo si aggiunge un’altra callback. Fai particolare attenzione se un binding normale non condiviso è già stato risolto. Nell’implementazione esaminata accade quanto segue.
  1. Viene registrata la nuova callback.
  2. Poiché resolved() è true, viene chiamato make().
  3. make() crea un nuovo oggetto e la callback viene eseguita nel relativo evento di risoluzione.
  4. La callback immediata viene eseguita anche sullo stesso oggetto restituito da make().
In questo percorso, la callback appena registrata viene applicata due volte allo stesso oggetto. Non riutilizzare così com’è con i binding normali un design pensato solo per il recupero di singleton.
Non inviare email, chiamare API esterne, effettuare addebiti o aggiungere listener senza condizioni all’interno della callback. Limitane l’uso all’applicazione idempotente della configurazione al servizio, in modo che nuove registrazioni o nuove risoluzioni non duplichino gli effetti collaterali.

Usare un’altra API per sostituire l’oggetto

Il valore restituito dalla callback afterResolving non viene usato per sostituire l’oggetto restituito dal container. Se vuoi restituire un decorator e sostituire il servizio stesso, valuta l’extend() del container. Il contratto della closure di questa API prevede che restituisca il servizio modificato. Allo stesso modo, callAfterResolving() non è un meccanismo che aggiorna tutte le dipendenze già salvate in altri oggetti. Se lo scopo è aggiornare le dipendenze al momento di un nuovo binding, consulta rebinding() nella documentazione ufficiale e la progettazione della classe interessata. Per i requisiti di un provider che carichi davvero i servizi in modo differito, consulta DeferrableProvider. Usare un hook e rendere differito il provider che registra quell’hook sono due cose distinte.

Combinazioni da verificare durante gli aggiornamenti

Prima di rilasciare il pacchetto, verifica non solo il normale ordine di avvio, ma anche il caso in cui un altro provider abbia usato il servizio in precedenza. Se registri con un flag statico che l’hook è stato usato una sola volta nell’intera applicazione, la configurazione potrebbe mancare nei servizi ricreati in un nuovo container o nei test. Per quanto possibile, garantisci l’idempotenza della configurazione a livello del singolo oggetto di destinazione o della chiave registrata.

Pagine correlate

Sovrascrivere e aggiornare le view di un pacchetto

Un esempio di come loadViewsFrom() usa un hook post-risoluzione per registrare il namespace delle view.

Sovrascrittura e aggiornamento delle traduzioni di un pacchetto

La registrazione del namespace nel Translator e la gestione delle traduzioni già caricate.

Fonti primarie consultate

Ultima modifica il 10 ottobre 2026