Dependency Injection verstehen
Dependency Injection verstehen
~16 Min. Lesezeit Zuletzt aktualisiert am 8. August 2026
Wir haben Autowiring bereits SEIT Kapitel 8 genutzt (LoggerInterface, Repositories, EntityManagerInterface), ohne das dahinterliegende Prinzip explizit zu benennen. Zeit, das Fundament nachzuholen, auf dem GANZ Symfony aufbaut.
Das Problem, das Dependency Injection löst
Stellen Sie sich vor, eine Klasse würde ihre Abhängigkeiten SELBST erzeugen:
class BenachrichtigungsService
{
public function sendeBenachrichtigung(string $nachricht): void
{
$logger = new \Monolog\Logger('app'); // fest verdrahtet!
$logger->info($nachricht);
}
}Drei konkrete Probleme: Die Klasse ist FEST an EINE bestimmte Logger-Implementierung gebunden (schwer austauschbar). Sie lässt sich NUR schwer isoliert testen (Kapitel 42 braucht dafür einen austauschbaren Fake-Logger). Und ändert sich, WIE der Logger konfiguriert wird, müssen ALLE Stellen angepasst werden, die ihn selbst erzeugen.
Die Lösung: Abhängigkeiten von außen hereinreichen
use Psr\Log\LoggerInterface;
class BenachrichtigungsService
{
public function __construct(
private readonly LoggerInterface $logger,
) {
}
public function sendeBenachrichtigung(string $nachricht): void
{
$this->logger->info($nachricht);
}
}GENAU dieses Muster kennen wir bereits aus JEDEM Controller in dieser Schulung – die Klasse fordert NUR ein Interface an (LoggerInterface, nicht die konkrete Logger-Klasse), OHNE zu wissen, WOHER die tatsächliche Implementierung kommt. Das Bereitstellen dieser Implementierung übernimmt Symfonys Service Container.
Der Service Container: Symfonys zentrale Fabrik
Der Container ist ein GROSSES Verzeichnis: "Wird LoggerInterface angefragt, liefere DIESE konkrete Instanz." Für JEDES use-Statement eines Constructor-Parameters prüft Symfony automatisch, ob eine passende Service-Definition existiert – GENAU das ist Autowiring.
php bin/console debug:containerListet ALLE registrierten Services – ein guter erster Anlaufpunkt bei der Fehlersuche, wenn Autowiring "nicht funktioniert" (meist: der gesuchte Service existiert schlicht nicht unter dem erwarteten Namen).
php bin/console debug:autowiring LoggerZeigt speziell, WELCHE Interfaces/Klassen mit "Logger" im Namen per Autowiring verfügbar sind – nützlich, um den EXAKTEN Typ für einen Constructor-Parameter zu finden.
Services sind standardmäßig Singletons
PRO Request wird JEDER Service NUR EINMAL instanziiert – fordern zehn verschiedene Klassen LoggerInterface an, erhalten ALLE ZEHN dieselbe Instanz. Das spart Speicher UND garantiert konsistenten Zustand (z. B. ein einmal geöffneter Datenbank-Connection wird wiederverwendet, statt zehnmal neu aufgebaut zu werden).
Dependency Injection vs. das Service-Locator-Anti-Pattern
Achtung: Widerstehen Sie der Versuchung, den Container DIREKT nach einem Service zu fragen ($container->get(LoggerInterface::class)) – das versteckt die tatsächlichen Abhängigkeiten einer Klasse VOR dem Leser und macht Tests schwerer. IMMER Abhängigkeiten explizit über den Constructor anfordern, wie in diesem Kapitel gezeigt – Symfony selbst nennt das direkte Container-Fragen ein "Service Locator"-Anti-Pattern und rät ausdrücklich davon ab.
Warum dieses Prinzip so zentral für Symfony ist
Tipp: Dependency Injection ist NICHT nur ein Detail – es ist der Grund, warum sich Symfony-Code in großen Teams gut warten lässt: JEDE Klasse dokumentiert ihre Abhängigkeiten SELBST (im Constructor), Abhängigkeiten lassen sich für Tests leicht durch Fakes ersetzen (Block 7), und das Austauschen einer Implementierung (z. B. ein anderer Mailer-Anbieter in Kapitel 38) berührt NUR die Konfiguration, nicht den Code, der sie nutzt.