Objektorientierung (OOP) – Verwalten der Dienste (Dependency Injection)

Klassen in PHP haben immer wieder Abhängigkeiten zu anderen Klassen – sogenannten Diensten (Service). Um diese möglichst flexibel und einfach verwalten zu können wird ein Service-Container benötigt. In diesem Blogbeitrag erläutere ich euch die Vorteile eines solchen Containers und gebe ein Beispiel wie er aussehen könnte.


Probleme mit Abhängigkeiten

Wozu wir einer globale Verwaltung unserer Dienste benötigen, lässt sich am besten durch ein Beispiel erklären. Die Ausgangssituation ist, dass ein Controller etwas aus dem Cache laden möchte.

Hier entsteht eine Abhängigkeit zu MyXCache. Ein UnitTest der Funktion würde immer auch MyXCache berühren, was zu unangenehmen Nebeneffekten führen kann, was die Funktion schwer testbar macht.

Sollte die Instanzierung der Klasse MyXCache unperformant sein oder projektbezogene Einstellungen benötigen (z. B. Datenbankkonfiguration), müssen wir die Kosten bei jedem Aufruf erneut bezahlen. Der selbe Dienst lässt sich nur schwer über mehrere Funktionen und Klassen hinweg zu teilen.

Ein weiterer Nachteil ist die schlechte Wartbarkeit des Programmcodes. Müssen wir einen Dienst austauschen (hier z. B. eine Umstellung auf einen anderen Cache), muss jede Stelle im Code geändert werden, die diesen Dienst benutzt.

Diese Probleme können alle mit entsprechender Dependency Injection gelöst werden.


Beispiel eines Service-Containers

Jedes PHP-Framework bietet seine eigene Form zur Verwaltung der Dienste. Symfony2 zum Beispiel versteckt den meisten Teil und erlaubt eine einfache Konfiguration über XML oder ähnliches. Phalcon zeigt etwas mehr des Prozesses und gibt uns den Container selbst zur Manipulation frei. Daran orientiert sich auch mein Beispiel.

Solltet ihr es also doch einmal selbst programmieren müssen, oder einfach wissen wollen wie es intern aussehen könnte, dann ist hier der entsprechende Code.


Verwendung

Definition der Dienste

Definiert werden unsere Dienste zu Beginn der Anwendung (Bootstrap) – im einfachsten Fall also direkt in der index.php.

Verwendung der Dienste

Mit einer derartigen Dependency Injection im Projekt verändert sich unser Beispiel von oben folgendermaßen:


UnitTests mit Depency Injection

Wie oben schon erwähnt, behindern feste Abhängigkeiten unsere Testmöglichkeiten. Jetzt allerdings können wir die notwendigen Dienste im Test als Mock-Objekte im Service-Container hinterlegen. Der zugehörige Test könnte dann zum Beispiel so aussehen:


Mehr zum Thema Objektorientierung