ÖFFENTLICHER SERVICE-UPDATE:
Ich habe viel gelernt, seit ich diese Frage gestellt habe. Wenn du das liest, bitte nimm meinen Rat und vermeide static
insgesamt. Gerade. Nicht. Benutzen. Es. Es gibt keine Möglichkeit zur Abhängigkeitsinjektion; Abhängigkeitsinjektion ist der Weg.
Ich habe kürzlich viel Zeit damit verbracht, verschiedene Konzepte der Inversion of Control ( IOC ) zu erforschen. Ich stimme völlig mit denen überein, die glauben, dass ein Service Locator ein Anti-Pattern ist. Ich baute eine, an der man basteln konnte, und war entsetzt über die Macht, die es erlaubte, "globale" Entitäten in der Mitte von Klassen zu importieren, indem man statische Locator-Methoden benutzte sowie die Möglichkeit, die tatsächlichen Abhängigkeiten eines Objekts zu verbergen.
Ausgehend vom Service-Locator habe ich einen Dependency-Injection-Container ( DI ) erstellt, der mir die Flexibilität des statischen Abhängigkeitszugriffs ohne die damit verbundenen Nachteile statischer Variablen bietet.
Hier ist ein einfaches Beispiel für eine solche Implementierung:
%Vor% Dies scheint ein Schritt in die richtige Richtung zu sein, da die statische Eigenschaft $params
geschützt ist und keine statischen Methoden für den Zugriff oder die Manipulation in einem "globalen" statischen Bereich vorhanden sind: Ein Objekt benötigt Zugriff auf den Container, um auf Abhängigkeiten zugreifen zu können / p>
Unglücklicherweise bedeutet das Speichern von Abhängigkeiten in diesem Container, dass nun jedes abhängigkeitsgesteuerte Objekt eine falsche Abhängigkeit vom Containerobjekt hat und somit seine echten Abhängigkeiten versteckt. Ein weiteres Negativ Nebeneffekt wäre, dass jedes Objekt Zugriff auf alle verfügbaren Abhängigkeiten im Container erhalten würde, und offensichtlich sollte ein Widget Objekt keinen Zugriff auf die Abhängigkeiten eines Kumquat -Objekts haben . Wenn Sie eine abstrakte Factory mit diesem Ansatz verwenden, wird die falsche Abhängigkeit nur aus den Klassen Widget und Kumquat in die Factory verschoben.
Mit den neuen Dereferenzierungsfunktionen von Object Construction konnten wir so etwas wie die folgenden ausführen, ohne auf die bereits erstellte $container
-Instanz im globalen Namespace zugreifen zu müssen:
Mit diesem Ansatz haben wir erfolgreich:
Nun besteht ein möglicher Nachteil darin, dass dieser Ansatz dazu führt, dass der Entwickler diszipliniert genug sein muss, um ein vollständiges Container
-Objekt nicht als Abhängigkeit zu übergeben. Das ist entscheidend.
In zwei Teilen:
Container::$params
sogar notwendig? Sollte es stattdessen eine standardmäßige geschützte Eigenschaft sein, auf die Top-of-the-Objekt-Graph-Factory-Klassen / Methoden im globalen Namespace trotzdem zugreifen (wodurch static
überflüssig wird)? Sie sollten static
hier überhaupt nicht verwenden. Erstellen Sie einfach einen Container: $container = new DIContainer();
und verwenden Sie dieses Objekt als typische Abhängigkeit. Schließlich gibt es im Kern der Anwendung nur wenige Stellen, die Zugriff auf den gesamten Container erfordern.
Sehen Sie sich Symfonys Dependency Injection-Komponente an - ein ziemlich guter Code.
Nach dem ersten Kommentar. Ja, du hast mich falsch verstanden. Normalerweise benötigen Sie nur einige Abhängigkeiten vom Container, also schreiben Sie etwas wie:
%Vor%Mein Punkt war, dass Sie keine statische Eigenschaft innerhalb des Containers verwenden sollten, da dies nichts anderes als ein globales Objekt ist. Es gäbe keinen Unterschied zwischen:
%Vor%Mit anderen Worten, der Container selbst sollte eine lokale Variable sein, und wenn Sie irgendwo anders darauf zugreifen müssen (einige Objekte benötigen möglicherweise Zugriff auf den gesamten Container), sollten Sie sie explizit als Abhängigkeit an dieses Objekt übergeben.
Wie bereits erwähnt, werfen Sie einen Blick auf Symfony DIC und das gesamte Framework, um zu sehen, wie man einen guten, gut geschriebenen DIC erstellt.
Einfacher Container:
%Vor%Ich mag die Idee nicht, einen neuen Container zu erstellen und ein globales Array zu teilen.
Die Lösung, ein Fassadenobjekt zu erstellen, erscheint mir besser:
%Vor%Im Bootstrap kann der IoC dann initialisiert werden:
%Vor%Und um den Container zu verwenden:
%Vor%Imho eine bessere Lösung als die Symphonie "Lösung". Der Container kann leicht durch eine andere Implementierung ersetzt werden, ohne irgendeinen anderen Code zu ändern. Und zum Testen verwenden Sie einfach eine neue Instanz von 'container', ohne das Fassadenobjekt.
Ich benutze eine Klasse wie diese von Laravel . Es erlaubt mir, Dinge wie folgt zu tun:
%Vor%Dies bedeutet, dass ich jede einzelne Klasse (oder Gruppe von Klassen) als kleines Plug-fähiges Modul registrieren kann, das vom IoC-Container verarbeitet wird. Dies erlaubt mir, diese Objekte zu überschreiben, wie es für Unit-Tests erforderlich ist, da jede Klasse niemals im Rest des PHP-Codes ad-hoc erstellt wird.
Tags und Links php dependency-injection