Korrigiert PHP Dereferenzierung von PHP 5.4 erfolgreich die Nachteile statischer Speicherparameter in diesem DI-Container?

8

Ö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>

Oh, warte ...

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.

Eine PHP 5.4 Alternative

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:

%Vor%

Mit diesem Ansatz haben wir erfolgreich:

  1. Behebung der Containerabhängigkeit von den Widget- und Kumquat-Objekten, wodurch deren Konstruktoren die spezifischen Abhängigkeitsobjekte, die sie benötigen, eingeben können:
  2. Verhinderte die Downstream-Widget- und Kumquat-Objekte, die Zugriff auf Abhängigkeiten haben, von denen sie nicht wissen sollten, dass sie existieren;
  3. Behält Speicherfunktionen für statische Abhängigkeiten bei.

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.

Also ist die Frage ...

In zwei Teilen:

  1. Welche konkreten Nachteile sehen Sie bei diesem Ansatz?
  2. Ist die statische 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)?
rdlowrey 07.02.2012, 16:05
quelle

3 Antworten

5

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.

BEARBEITEN:

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%     
Crozin 07.02.2012, 16:50
quelle
2

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.

    
JvdBerg 01.09.2012 13:00
quelle
0

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.

    
Xeoncross 07.02.2012 17:35
quelle

Tags und Links