Dependency Injection
Fa parte della sezione Programmazione orientata agli oggetti del percorso PHP di Coddy. Lezione 57 di 91.
Nella lezione precedente, hai visto come la composizione consente a una Car di contenere un oggetto Engine. Ma creare dipendenze all'interno della classe presenta un problema: rende il codice rigido e difficile da testare. L'iniezione delle dipendenze risolve questo problema passando le dipendenze dall'esterno invece di crearle internamente.
Confronta questi due approcci:
<?php
// Senza DI - dipendenza creata internamente
class Car {
private Engine $engine;
public function __construct() {
$this->engine = new Engine(); // Strettamente accoppiato
}
}
// Con DI - dipendenza passata dall'esterno
class Car {
public function __construct(private Engine $engine) {}
}
$engine = new Engine();
$car = new Car($engine); // Iniettato dall'esterno
Il secondo approccio è l'iniezione delle dipendenze. La Car non crea il proprio motore: ne riceve uno. Questo semplice cambiamento offre vantaggi notevoli: puoi passare diversi tipi di motore, sostituire le implementazioni per i test e rendere la classe più flessibile.
Per una flessibilità ancora maggiore, inietta interfacce invece di classi concrete:
<?php
interface EngineInterface {
public function start(): string;
}
class Car {
public function __construct(private EngineInterface $engine) {}
public function start(): string {
return $this->engine->start();
}
}
Ora Car funziona con qualsiasi classe che implementi EngineInterface - un motore a benzina, un motore elettrico o un mock per i test. Questo disaccoppiamento è il motivo per cui l'iniezione delle dipendenze è fondamentale per scrivere applicazioni PHP manutenibili e testabili.
Sfida
FacileCostruiamo un sistema di notifiche che dimostri la potenza dell'iniezione delle dipendenze. Invece di definire in modo rigido come vengono inviati i messaggi, creerai un sistema flessibile in cui è facile sostituire il metodo di invio.
Organizzerai il codice in quattro file:
MessageSenderInterface.php: Definisci un'interfaccia chiamataMessageSenderInterfacecon un unico metodosend(string $recipient, string $message): string. Questa interfaccia stabilisce il contratto che ogni mittente di messaggi deve rispettare.EmailSender.php: Crea una classeEmailSenderche implementaMessageSenderInterface. Includi il file dell'interfaccia. Il metodosend()deve restituire"Email to [recipient]: [message]".NotificationService.php: Crea una classeNotificationServiceche riceve la propria dipendenza tramite il costruttore. Includi il file dell'interfaccia. La classe deve:- Accettare un
MessageSenderInterfacenel costruttore usando la promozione delle proprietà del costruttore - Avere un metodo
notify(string $recipient, string $message)che delega al mittente iniettato e ne restituisce il risultato
NotificationServicedipenda dall'interfaccia, non da una classe concreta. Ciò significa che puoi iniettare qualsiasi mittente che implementi l'interfaccia senza modificare il servizio.- Accettare un
main.php: Includi i file EmailSender e NotificationService. Riceverai due input: un destinatario e un messaggio. Crea unEmailSender, iniettalo in unNotificationService, poi chiamanotify()e stampa il risultato.
Questo schema mantiene flessibile il tuo NotificationService. Funziona con qualsiasi mittente tu inietti, che si tratti di email, SMS o qualcosa che non hai ancora creato. Il servizio non crea le proprie dipendenze: le riceve dall'esterno.
Provalo tu
<?php
require_once 'EmailSender.php';
require_once 'NotificationService.php';
// Leggi l'input
$recipient = trim(fgets(STDIN));
$message = trim(fgets(STDIN));
// TODO: Crea un'istanza di EmailSender
// TODO: Iniettala in un'istanza di NotificationService
// TODO: Chiama notify() e stampa il risultato
?>Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Fondamenti della programmazione orientata agli oggetti
File esterniIntroduzione alla programmazione orientata agli oggettiClassi e oggettiLa parola chiave $thisMetodiProprietàCostruttore (__construct)Distruttore (__destruct)Riepilogo - Calcolatrice semplice4Ereditarietà
Ereditarietà di baseLa parola chiave parent::Sovrascrittura dei metodiLa parola chiave finalClassi astratteRiepilogo - Gerarchia dei dipendenti7Incapsulamento
Pubblico, Protetto, PrivatoApprofondimento sui modificatori di accessoGetter e SetterOccultamento delle informazioniPromozione dei parametri del costruttore (8.0)Riepilogo - Sistema di gestione dei registri degli studenti10Concetti avanzati di programmazione a oggetti
Composizione vs ereditarietàDependency InjectionClassi anonimeEnumerazioni (PHP 8.1)Fibers (PHP 8.1)Approfondimento sulla clonazione degli oggettiGeneratori e iteratori13Modelli di progettazione, parte 2
Modello CommandModello AdapterModello DecoratorModello Template MethodModello StateModello CompositeModello Repository2Namespace e autoloading
Introduzione ai namespaceLa keyword useStandard di autoloading PSR-4Autoloader di ComposerRiepilogo - Progetto organizzato5Interfacce e contratti
Introduzione alle interfacceImplementare le interfacceImplementare più interfacceInterfaccia vs classe astrattaType hinting con le interfacceRiepilogo - Calcolatore di forme8Metodi magici
Introduzione ai metodi magici__toString e __debugInfo__get, __set, __isset, __unset__call e __callStatic__clone e clonazione degli oggetti__serialize e __unserializeRiepilogo - Collezione personalizzata11Sistema dei tipi e gestione degli errori
Dichiarazioni di tipoTipi nullableTipi unione e intersezioneClassi di eccezioneGerarchia di eccezioni personalizzataTry, Catch, FinallyRiepilogo - Validatore di moduli14Progetto: Gestione della biblioteca
Panoramica del progettoClassi Libro e Utente3Proprietà delle classi
Proprietà di istanza e staticheCostanti nelle classiMetodi e proprietà staticiProprietà private e protectedProprietà readonly (PHP 8.1)Riepilogo - Gestore di conti bancari6Polimorfismo
Ridefinizione dei metodi, ripresaPolimorfismo tramite interfacceSuggerimenti sui tipi e tipi UnionBinding statico tardivoRiepilogo - Processore di pagamenti9Tratti
Introduzione ai trattiUtilizzare più trattiRisoluzione dei conflitti tra trattiMetodi astratti nei trattiTratti vs ereditarietà12Design pattern - Parte 1
Introduzione ai design patternPattern SingletonPattern FactoryPattern ObserverPattern StrategyEsercitati da solo: Compilatore PHP online