Dependency Injection
Teil des Abschnitts Objektorientierte Programmierung der PHP-Journey von Coddy. Lektion 57 von 91.
In der vorherigen Lektion hast du gesehen, wie Komposition es einem Car ermöglicht, ein Engine-Objekt zu enthalten. Aber das Erstellen von Abhängigkeiten innerhalb der Klasse bringt ein Problem mit sich – es macht den Code starr und schwer zu testen. Dependency Injection löst dieses Problem, indem Abhängigkeiten von außen übergeben werden, anstatt sie intern zu erstellen.
Vergleiche diese beiden Ansätze:
<?php
// Ohne DI - Abhängigkeit intern erstellt
class Car {
private Engine $engine;
public function __construct() {
$this->engine = new Engine(); // Eng gekoppelt
}
}
// Mit DI - Abhängigkeit wird übergeben
class Car {
public function __construct(private Engine $engine) {}
}
$engine = new Engine();
$car = new Car($engine); // Von außen injiziert
Der zweite Ansatz ist Dependency Injection. Das Car erstellt seinen eigenen Motor nicht selbst – es erhält einen. Diese einfache Änderung bietet bedeutende Vorteile: Du kannst verschiedene Motortypen übergeben, Implementierungen zum Testen austauschen, und die Klasse wird flexibler.
Für noch größere Flexibilität kannst du Schnittstellen statt konkreter Klassen injizieren:
<?php
interface EngineInterface {
public function start(): string;
}
class Car {
public function __construct(private EngineInterface $engine) {}
public function start(): string {
return $this->engine->start();
}
}
Jetzt funktioniert Car mit jeder Klasse, die EngineInterface implementiert – einem Benzinmotor, einem Elektromotor oder einem Mock für Tests. Diese Entkopplung ist der Grund, warum Dependency Injection für das Schreiben wartbarer und testbarer PHP-Anwendungen grundlegend ist.
Aufgabe
EinfachErstellen wir ein Benachrichtigungssystem, das die Leistungsfähigkeit der Abhängigkeitsinjektion demonstriert. Statt fest zu codieren, wie Nachrichten gesendet werden, erstellst du ein flexibles System, bei dem die Zustellmethode einfach ausgetauscht werden kann.
Du organisierst deinen Code über vier Dateien:
MessageSenderInterface.php: Definiere ein Interface namensMessageSenderInterfacemit einer einzigen Methodesend(string $recipient, string $message): string. Dieses Interface legt den Vertrag fest, den jeder Nachrichtenversender einhalten muss.EmailSender.php: Erstelle eine KlasseEmailSender, dieMessageSenderInterfaceimplementiert. Binde die Interface-Datei ein. Die Methodesend()soll"Email to [recipient]: [message]"zurückgeben.NotificationService.php: Erstelle eine KlasseNotificationService, die ihre Abhängigkeit über den Konstruktor erhält. Binde die Interface-Datei ein. Die Klasse soll:- In ihrem Konstruktor mithilfe der Konstruktor-Promotion ein
MessageSenderInterfaceakzeptieren - Eine Methode
notify(string $recipient, string $message)besitzen, die die Aufgabe an den injizierten Sender delegiert und dessen Ergebnis zurückgibt
NotificationServicevom Interface und nicht von einer konkreten Klasse abhängt. Das bedeutet, dass du jeden Sender injizieren könntest, der das Interface implementiert, ohne den Service zu ändern.- In ihrem Konstruktor mithilfe der Konstruktor-Promotion ein
main.php: Binde die Dateien für EmailSender und NotificationService ein. Du erhältst zwei Eingaben: einen Empfänger und eine Nachricht. Erstelle einEmailSender, injiziere es in einenNotificationService, rufe anschließendnotify()auf und gib das Ergebnis aus.
Dieses Muster hält deinen NotificationService flexibel. Er funktioniert mit jedem Sender, den du injizierst, unabhängig davon, ob es sich um E-Mail, SMS oder etwas handelt, das du noch nicht erstellt hast. Der Service erstellt seine Abhängigkeiten nicht selbst, sondern erhält sie von außen.
Probier es selbst
<?php
require_once 'EmailSender.php';
require_once 'NotificationService.php';
// Eingabe lesen
$recipient = trim(fgets(STDIN));
$message = trim(fgets(STDIN));
// TODO: Erstelle eine EmailSender-Instanz
// TODO: Injiziere sie in einen NotificationService
// TODO: Rufe notify() auf und gib das Ergebnis aus
?>Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienEinführung in OOPKlassen vs. ObjekteDas Schlüsselwort $thisMethodenEigenschaftenKonstruktor (__construct)Destruktor (__destruct)Rückblick – Einfacher Taschenrechner4Vererbung
Grundlegende VererbungDas Schlüsselwort parent::MethodenüberschreibungDas Schlüsselwort finalAbstrakte KlassenRückblick – Mitarbeiterhierarchie7Kapselung
Öffentlich, geschützt, privatZugriffsmodifikatoren im DetailGetter und SetterInformationsverbergungKonstruktor-Promotion (8.0)Wiederholung – System zur Verwaltung von Schülerdatensätzen10Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungDependency InjectionAnonyme KlassenEnums (PHP 8.1)Fibers (PHP 8.1)Objektklonen im DetailGeneratoren & Iteratoren2Namespaces & Autoloading
Einführung in NamespacesDas use-SchlüsselwortPSR-4-Autoloading-StandardComposer-AutoloaderRückblick – Organisiertes Projekt5Schnittstellen & Verträge
Einführung in SchnittstellenSchnittstellen implementierenMehrere Schnittstellen implementierenSchnittstelle vs. abstrakte KlasseTyp-Hinweise mit SchnittstellenRückblick – Formrechner8Magische Methoden
Einführung in magische Methoden__toString & __debugInfo__get, __set, __isset, __unset__call & __callStatic__clone & Objektklonen__serialize & __unserializeRückblick – Benutzerdefinierte Sammlung11Typsystem & Fehlerbehandlung
TypdeklarationenNullable-TypenUnion- & Intersection-TypenException-KlassenBenutzerdefinierte Exception-HierarchieTry, Catch, FinallyRückblick – Formularvalidator14Projekt: Bibliotheksverwaltung
ProjektübersichtBuch- und Benutzerklassen3Klassen-Eigenschaften
Instanz- vs. statische EigenschaftenKonstanten in KlassenStatische Methoden & EigenschaftenPrivate & geschützte EigenschaftenSchreibgeschützte Eigenschaften (PHP 8.1)Zusammenfassung – Bankkonto-Manager6Polymorphie
Methodenüberschreibung erneut betrachtetPolymorphie über SchnittstellenTyp-Hinweise & Union-TypenSpätes statisches BindenRückblick – Zahlungsabwickler9Traits
Einführung in TraitsMehrere Traits verwendenAuflösung von Trait-KonfliktenAbstrakte Methoden in TraitsTraits vs. Vererbung12Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory-MusterObserver-MusterStrategy-Muster15Abschließende Herausforderungen
E-Learning-PlattformBankingsystemEntwicklung einer SpielfigurFahrzeugvermietungÜbe selbstständig: Online-PHP-Compiler