Cablaggio auto
L'autowiring è un'ottima funzione che permette di passare automaticamente i servizi al costruttore e ad altri metodi, senza doverli scrivere. Permette di risparmiare molto tempo.
Questo ci permette di saltare la maggior parte degli argomenti quando scriviamo le definizioni dei servizi. Invece di:
Scrivete:
Il cablaggio automatico è guidato dai tipi, quindi la classe ArticleRepository
deve essere definita
come segue:
Per usare l'autowiring, deve esserci un solo servizio per ogni tipo nel contenitore. Se ce ne fossero di più, l'autowiring non saprebbe quale passare e lancerebbe un'eccezione:
La soluzione sarebbe quella di bypassare l'autowiring e dichiarare esplicitamente il nome del servizio (per esempio
articles: Model\ArticleRepository(@mainDb)
). Tuttavia, è più conveniente disabilitare l' autowiring di un solo servizio, o del primo servizio preferito.
Cablaggio automatico disabilitato
È possibile disabilitare il cablaggio automatico del servizio utilizzando l'opzione autowired: no
:
Il servizio articles
non lancia l'eccezione che ci sono due servizi corrispondenti di tipo PDO
(cioè
mainDb
e tempDb
) che possono essere passati al costruttore, perché vede solo il servizio
mainDb
.
La configurazione dell'autowiring in Nette funziona in modo diverso rispetto a Symfony, dove l'opzione
autowire: false
dice che l'autowiring non deve essere usato per i parametri del costruttore di servizi. In Nette,
l'autowiring è sempre usato, sia per i parametri del costruttore che per qualsiasi altro metodo. L'opzione
autowired: false
dice che l'istanza del servizio non deve essere passata da nessuna parte usando l'autowiring.
Autowiring preferito
Se abbiamo più servizi dello stesso tipo e uno di essi ha l'opzione autowired
, questo servizio diventa quello
preferito:
Il servizio articles
non lancia l'eccezione che ci sono due servizi PDO
corrispondenti (cioè
mainDb
e tempDb
), ma utilizza il servizio preferito, cioè mainDb
.
Raccolta di servizi
L'autowiring può anche passare un array di servizi di un tipo particolare. Poiché PHP non è in grado di annotare nativamente
il tipo di elementi dell'array, oltre al tipo array
, è necessario aggiungere un commento phpDoc con il tipo di
elemento come ClassName[]
:
Il contenitore DI passa automaticamente un array di servizi che corrispondono al tipo dato. Ometterà i servizi che hanno il cablaggio automatico disattivato.
Il tipo nel commento può anche essere della forma array<int, Class>
oppure list<Class>
.
Se non si può controllare la forma del commento di phpDoc, si può passare un array di servizi direttamente nella configurazione
usando typed()
.
Argomenti scalari
Il cablaggio automatico può passare solo oggetti e array di oggetti. Gli argomenti scalari (ad esempio stringhe, numeri, booleani) si scrivono nella configurazione. Un'alternativa è quella di creare un oggetto settings che incapsuli un valore scalare (o più valori) come un oggetto, che può essere passato di nuovo con l'autowiring.
Si crea un servizio aggiungendolo alla configurazione:
Tutte le classi lo richiederanno quindi tramite il cablaggio automatico.
Restringimento del cablaggio automatico
Per i singoli servizi, il cablaggio automatico può essere ristretto a classi o interfacce specifiche.
Normalmente, l'autowiring passa il servizio a ogni parametro del metodo al cui tipo il servizio corrisponde. Restringere significa specificare le condizioni che i tipi specificati per i parametri del metodo devono soddisfare affinché il servizio venga passato ad essi.
Facciamo un esempio:
Se li registrassimo tutti come servizi, il cablaggio automatico fallirebbe:
Il servizio parentDep
lancia l'eccezione Multiple services of type ParentClass found: parent, child
perché sia parent
che child
si inseriscono nel suo costruttore e l'autowiring non può decidere quale
scegliere.
Per il servizio child
, possiamo quindi restringere il suo autowiring a ChildClass
:
Il servizio parentDep
viene ora passato al costruttore del servizio parentDep
, poiché ora è l'unico
oggetto corrispondente. Il servizio child
non viene più passato per autocablaggio. Sì, il servizio
child
è ancora di tipo ParentClass
, ma la condizione di restringimento data per il tipo di parametro
non si applica più, cioè non è più vero che ParentClass
è un supertipo di ChildClass
.
Nel caso di child
, autowired: ChildClass
potrebbe essere scritto come autowired: self
,
poiché self
indica il tipo di servizio corrente.
La chiave autowired
può includere diverse classi e interfacce come array:
Proviamo ad aggiungere le interfacce all'esempio:
Se non limitiamo il servizio child
, esso entrerà nei costruttori di tutte le classi FooDependent
,
BarDependent
, ParentDependent
e ChildDependent
e l'autowiring lo passerà lì.
Tuttavia, se restringiamo il suo autowiring a ChildClass
usando autowired: ChildClass
(o
self
), l'autowiring lo passa solo al costruttore ChildDependent
, perché richiede un argomento di tipo
ChildClass
e ChildClass
è di tipo ChildClass
. Nessun altro tipo specificato per
gli altri parametri è un superset di ChildClass
, quindi il servizio non viene passato.
Se lo limitiamo a ParentClass
usando autowired: ParentClass
, l'autowiring lo passerà di nuovo al
costruttore ChildDependent
(poiché il tipo richiesto ChildClass
è un sottoinsieme di
ParentClass
) e anche al costruttore ParentDependent
, poiché anche il tipo richiesto di
ParentClass
corrisponde.
Se lo limitiamo a FooInterface
, si autocablerà ancora a ParentDependent
(il tipo richiesto
ParentClass
è un supertipo di FooInterface
) e a ChildDependent
, ma anche al costruttore
FooDependent
, ma non a BarDependent
, poiché BarInterface
non è un supertipo di
FooInterface
.