In primo luogo, voglio limitare questa domanda solo allo sviluppo web. Quindi questo è indipendente dal linguaggio finché il linguaggio viene utilizzato per lo sviluppo web. Personalmente, sto arrivando a questo da uno sfondo in PHP.Quale è meglio: Iniezione delle dipendenze + Registro o Iniezione delle dipendenze o Registro globale?
Spesso è necessario utilizzare un oggetto da più ambiti. Ad esempio, potrebbe essere necessario utilizzare una classe di database nell'ambito normale ma anche da una classe di controller. Se creiamo l'oggetto del database in ambito normale, non possiamo accedervi dall'interno della classe controller. Desideriamo evitare di creare due oggetti di database in ambiti diversi e quindi abbiamo bisogno di un modo per riutilizzare la classe del database indipendentemente dall'ambito. Per fare ciò, abbiamo due opzioni:
- Rendere globale l'oggetto del database in modo che sia accessibile da qualsiasi luogo.
- Passa la classe del database alla classe controller sotto forma, ad esempio, di un parametro nel costruttore del controllore. Questo è noto come iniezione di dipendenza (DI).
Il problema diventa più complesso quando ci sono molte classi coinvolte tutti gli oggetti esigenti in molti ambiti diversi. In entrambe le soluzioni, questo diventa problematico perché se rendiamo globale uno dei nostri oggetti, stiamo mettendo troppo rumore nello scope globale e se passiamo troppi parametri in una classe, la classe diventa molto più difficile da gestire.
Pertanto, in entrambi i casi, si vede spesso l'uso di un registro. Nel caso globale, abbiamo un oggetto di registro che è reso globale e quindi aggiunge tutti i nostri oggetti e variabili a quelli che li rendono disponibili in qualsiasi oggetto, ma inserendo una sola variabile, il registro, nello scope globale. Nel caso DI, passiamo l'oggetto del Registro di sistema in ogni classe riducendo il numero di parametri a 1.
Personalmente, utilizzo quest'ultimo approccio a causa dei numerosi articoli che lo sostengono sull'utilizzo di globals ma ho riscontrato due problemi. In primo luogo, la classe di registro conterrà enormi quantità di ricorsione. Ad esempio, la classe del Registro di sistema conterrà le variabili di accesso al database richieste dalla classe del database. Pertanto, è necessario inserire la classe di registro nel database. Tuttavia, il database sarà necessario per molte altre classi e quindi il database dovrà essere aggiunto al registro, creato un ciclo. Le lingue moderne possono gestire questo problema o questo sta causando enormi problemi di prestazioni? Si noti che il registro globale non ne risente poiché non viene passato a nulla.
In secondo luogo, inizierò a passare grandi quantità di dati a oggetti che non ne hanno bisogno. Al mio database non interessa il mio router ma il router verrà passato al database insieme ai dettagli della connessione al database. Ciò è aggravato dal problema della ricorsione perché se il router ha il registro, il registro ha il database e il registro e il registro viene passato al database, quindi il database viene passato a se stesso tramite il router (cioè posso fare $this->registry->router->registry->database
dall'interno della classe del database `).
Inoltre, non vedo ciò che il DI mi sta dando se non più complessità. Devo passare una variabile extra in ogni oggetto e devo usare gli oggetti di registro con $this->registry->object->method()
invece di $registry->object->method()
. Questo ovviamente non è un grosso problema, ma sembra inutile se non mi dà nulla rispetto all'approccio globale.
Ovviamente, questi problemi non esistono quando utilizzo DI senza un registro ma poi devo passare ogni oggetto "manualmente", ottenendo costruttori di classe con un numero ridicolo di parametri.
Dato questi problemi con entrambe le versioni di DI, non è un registro globale superiore?Cosa sto perdendo usando un registro globale su DI?
Una cosa che viene spesso menzionata quando si parla di DI contro Globali è che i globali inibiscono la capacità di testare correttamente il programma. In che modo esattamente i globals mi impediscono di provare un programma in cui DI non lo farebbe? Ho letto in molti posti che ciò è dovuto al fatto che un globale può essere modificato da qualsiasi luogo e quindi è difficile deridere. Tuttavia, mi sembra che, almeno in PHP, gli oggetti siano passati per riferimento, cambiando un oggetto iniettato in qualche classe lo cambierai anche in qualsiasi altra classe in cui è stato iniettato.
Bene, un piccolo punto. In PHP 5 (penso che 5.2, ma potrebbe essere stato precedente) tutti gli oggetti vengono passati per riferimento quando vengono passati a metodi/funzioni. Quindi non stai effettivamente spostando un sacco di dati, stai solo incrementando il conteggio dei riferimenti e spostando ciò che si riduce a un puntatore ... (A cui ti accengi più avanti nel post) ... – ircmaxell
Questo significa che non ci dovrebbero essere differenze in termini di prestazioni tra il passaggio di un oggetto senza proprietà e un oggetto con 1000 proprietà (tranne ovviamente per la differenza originale quando vengono inizializzate)? La ricorsione lo altera in qualche modo? –
La ricorsione è un problema, non è possibile, ad esempio, distruggere un oggetto quando lo si desidera, a meno che tutti i riferimenti all'oggetto non vengano distrutti. L'inserimento di debug_backtrace() in qualche __destructor spesso rende lo script interrotto, questo solo a causa delle ricorsioni. È bene che tu menzioni la ricorsione, dovresti prenderla in seria considerazione. Penso che l'iniezione renda la ricorsione ancora peggiore. Per quanto riguarda la connessione al database, una funzione globale get_db_conn() potrebbe fare il lavoro bene, tutto ciò che serve è mettere un $ statico database_conn = null; all'interno della funzione get_db_conn(). – Melsi