Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Utilizzo della Dependency Injection in PHP

Cosa sono, a cosa servono e come si usano le Dependency Injection in PHP, gli strumenti per ridurre gli errori nel gestire le dipendenze fra classi
Cosa sono, a cosa servono e come si usano le Dependency Injection in PHP, gli strumenti per ridurre gli errori nel gestire le dipendenze fra classi
Link copiato negli appunti

Non di rado l’esistenza di vincoli di dipendenza tra le classi disponibili rende difficoltoso lo sviluppo di codici sorgenti che siano leggibili e caratterizzati da componenti facilmente riutilizzabili. Nel corso di questa breve trattazione, verrà descritto il funzionamento del Design pattern Dependency Injection come soluzione valida per ridurre al minimo gli effetti collaterali dovuti alla sussistenza di dipendenze tra classi.

Il concetto di dipendenza tra le classi

La gestione delle dipendenze tra le classi è un problema abbastanza ricorrente nella realizzazione di applicazioni complesse scritte in PHP e il cui codice sia basato sul paradigma della programmazione orientata agli oggetti; sostanzialmente una “dipendenza” è definibile in programmazione come il vincolo esistente tra le varie componenti che costituiscono un’applicazione, tale legame stabilisce in pratica il livello di relazione per il quale il funzionamento di una parte “dipende” dalla natura e dalla presenza delle altre parti.

Quanto detto è traducibile dal punto di vista dell’Object Oriented Programming facendo riferimento al meccanismo della classi. Si ipotizzi di disporre di due classi, denominate rispettivamente “Automobile” e “Benzina”, nel caso in cui la classe “Automobile” debba utilizzare la classe “Benzina” si dirà che la prima classe dipende dalla seconda; ciò significa inoltre che “Automobile” (dipendente) non funzionerà senza “Benzina” (dipendenza) e che non si potrà utilizzare la prima senza coinvolgere la seconda.

L’esempio proposto fa emergere il problema implicito nella presenza delle dipendenze, esse infatti influenzano negativamente il grado di flessibilità di un progetto perché limitano le opportunità di reimpiego delle classi, lo sviluppatore dovrà infatti tenere sempre presente le implicazioni dovute all’adozione di una classe se per il suo funzionamento essa necessita di un ulteriore modello per la creazione di oggetti.

Caratteristiche della Dependency Injection

Un sistema per la risoluzione delle problematiche correlate alle dipendenze fa riferimento all’utilizzo di un pattern, cioè di uno schema progettuale, che prende il nome di Dependency Injection; in pratica, quest’ultimo permetterà di effettuare iniezioni di oggetti nel contesto di una classe evitando di doverli generare all’interno di essa. Per chiarire la meccanica dell’iniezione di dipendenze è possibile partire da un caso pratico e cioè dall’origine del problema; si parta quindi dalla definizione della seguente classe:

class Dipendente
{
    private $_vincolo;
    public function __construct($pippo, $pluto)
    {
        $this->_vincolo = new Dipendenza($pippo, $pluto);
    }
}
$oggetto = new Dipendente('pippo', 'pluto');

Dal punto di vista sintattico il codice presentato non include particolari problematiche o complessità, ma rianalizzandolo a livello funzionale è possibile osservare l’esistenza di un vincolo di dipendenza a carico del costruttore, quest’ultimo genera un legame tra la classe “Dipendente” e la classe “Dipendenza”; ne consegue che il verificarsi di un evento, come per esempio l’inserimento di un parametro passato alla dipendenza, influirà su qualsiasi istanza della sua dipendente.

Nel caso di un’eventualità del genere, potrebbe tornare utile il discorso relativo alla Dependency Injection, questo perché essa darà allo sviluppatore la possibilità di inserire la dipendenza senza la necessità di doverla generare nel costruttore della classe; sulla base di quanto anticipato si potrà modificare il codice precedentemente proposto nel modo seguente:

class Dipendente
{
    private $_vincolo;
    public function __construct($vincolo)
    {
        $this->_vincolo = $vincolo;
    }
}
$vincolo = new Dipendenza('pippo', 'pluto');
$oggetto = new Dipendente($vincolo);

Quanto contenuto nell’esempio mostrato riassume la modalità più diffusa per l’utilizzo della Dependency Injection, cioè quella che prevede i passaggio delle dipendenze al costruttore di classe, è però possibile fare in modo che le dipendenze vengano iniettate anche tramite metodi e proprietà; da notare poi come nel caso del codice proposto l’inserimento di nuovi parametri tramite l’istanza dell’oggetto di classe della dipendenza non avrà influenza sulle istanze relative alla dipendente:

$vincolo = new Dipendenza('pippo', 'pluto', 'paperino');
$oggetto = new Dipendente($vincolo);

Un altro evidente vantaggio nell’uso della Dependency Injection sta nel fatto che, grazie ad essa, la dipendenza potrà essere configurata indipendentemente dal vincolo che la lega alla componente dipendente, per cui la prima potrà essere anche rimpiazzata con un’altra senza per questo dover intervenire in alcun modo sulla seconda.

Modalità di applicazione della Dependency Injection

Lo sviluppatore avrà a disposizione diverse modalità per la gestione delle dipendenze tramite la loro iniezione, ma è comunque possibile effettuare un distinzione in tre tipologie ognuna associata a differenti implicazioni. La Field Injection, altrimenti detta “Property Injection”, consiste in pratica nell’iniezione diretta delle dipendenze all’interno delle proprietà di classe con livello di visibilità pubblico; un esempio del suo utilizzo potrebbe essere il seguente:

$vincolo = new Dipendenza();
$oggetto = new Dipendente();
$oggetto->_vincolo = $vincolo;

Pur trattandosi di una tecnica di veloce utilizzo, essa presenta lo svantaggio di non supportare il Type Hinting utile per forzare l’uso di uno specifico tipo di oggetto quale parametro; dato che in sua assenza il parser di PHP non produrrà la notifica di errore prevista in caso di mancato rispetto del tipo suggerito, non sarà possibile avere la certezza che il tipo associato ad una dipendenza sia quello corretto.

La Setter Injection funziona in modo simile alla Field Injection ma, nello specifico, basa il suo funzionamento su costruttori privi di argomenti e sul passaggio di dipendenze attraverso “setter”, cioè metodi che scrivono attributi e che possono essere resi riconoscibili tramite la chiave “init” posta davanti alla radice del loro nome:

$vincolo = new Dipendenza();
$oggetto = new dipendente();
$oggetto->initVincolo($vincolo);

La Setter Injection consente di inserire parzialmente le dipendenze e le rende facoltative in quanto legate all’eventuale chiamata del metodo setter, inoltre, facilita l’alterazione degli oggetti permettendo di iniettare nuovamente le dipendenze attraverso chiamate multiple al setter. Questa modalità non si rivela però particolarmente funzionale quando si deve gestire un gran numero di dipendenze, esse infatti necessiteranno di un’analoga quantità di metodi setter.

La Constructor Injection, già utilizzata negli esempi proposti dal capitolo precedente, sfrutta una logica secondo la quale tutte le iniezioni di dipendenze dovranno avvenire a carico del costruttore e di conseguenza precedentemente alle istanze. Questo significa che, dato che un oggetto non potrà essere istanziato senza dipendenza, essa dovrà essere necessariamente presente al momento dell’istanza; ciò non avverrà invece nel caso della Setter Injection dove le chiamata ai metodi setter è opzionale e si potrà verificare l’iniezione delle dipendenze soltanto attraverso dei controlli.

L’utilizzo di espressioni basate sulla Constructor Injection come le seguenti

$vincolo = new Dipendenza();
$oggetto = new Dipendente($vincolo);

renderà certa l’immutabilità della dipendenza per tutto il periodo di esecuzione nel quale esisterà l’oggetto creato, questo a causa dell’unica chiamata che coinvolgerà il costruttore, inoltre, sarà più semplice gestire un alto numero di dipendenze grazie ad un solo costruttore relativo a più parametri.

Se da una parte la Constructor Injection consente di inizializzare gli oggetti in modo ordinato e non necessita di una metodo setter per ogni dipendenza, è però necessario sottolineare che essa non permette di iniettare le dipendenze in modo parziale proprio per via del fatto che per la creazione di un oggetto sarà richiesto il passaggio di tutti gli argomenti al costruttore; andrebbe poi ricordato il limite dovuto all’impossibilità di modificare un oggetto.

Ricordando il mancato supporto del Type Hinting da parte della Field Injection, non è semplice stabilire a priori quale modalità sia preferibile tra la Setter Injection e la Constructor Injection, molto dipenderà dalla necessità dello sviluppatore di operare o meno con dipendenze opzionali (un punto a favore della Setter Injection) o dell’importanza che la sequenza di inizializzazione degli oggetti avrà per il progetto implementato (un punto a favore della Constructor Injection).

Conclusioni

In questa trattazione è stato affrontato il discorso relativo alla gestione delle dipendenze in PHP tramite il pattern Dependency Injection; di quest’ultimo sono state descritte le caratteristiche, la sintassi e le diverse modalità di utilizzo, proponendo al lettore le opportunità e i limiti delle varie tecniche disponibili per la riduzione degli effetti negativi delle dipendenze su leggibilità e del codice e flessibilità.

Neanche la Dependency Injection è facilmente applicabile in tutti i casi nei quali si debbano gestire le dipendenze, questo perché il suo utilizzo in un progetto necessita di un’attenta pianificazione “a monte”, nel lungo periodo può però rivelarsi un ottimo alleato per le operazioni di manutenzione e aggiornamento dei sorgenti.

Ti consigliamo anche