Hallo,
Es kommt ja durchaus vor, dass irgendwelche Komponenten weitere Subkomponenten erzeugen müssen, und wenn ich alles von "ganz oben" hinein injizieren will, habe ich am Ende eine unüberschaubare Parameterleiste.
Eine Komponente sollte weder wissen, wo sie verwendet wird, noch welche Abhängigkeiten ihre eigenen Abhängigkeiten haben. Das macht die Parameterliste sehr klein.
Die Komplexität des Abhängigkeitsbaums besteht ja nur beim Aufbau, was aber meistens anderswo als in der Klasse selber geschieht. Wenn man natürlich keine Hilfe verwendet (irgendeine Library, die die Instanziierungslogik generiert aus Annotationen/Config/...) ist das unter Umständen sehr langwierig, da stimme ich zu. Aber nichtsdestotrotz sollte eine einzelne Abhängigkeitsliste einer Klasse kurz sein - und wenn sie zu lang werden sollte sollte man sich auch fragen, ob man diese Klasse teilen kann.
Der Controller braucht dann Zugriff auf die DB-Repositories und muss passende Views erzeugen - die kann und will ich nicht aus dem Router injizieren. Ich brauche also eine View-Factory, DIE kann ich injizieren und für Tests einen Ersatz [1] unterschieben.
Ich fange mal mit dem zwischengeschobenen "die kann und will ich nicht aus dem Router injizieren" an: das ist vollkommen korrekt. Der Router sollte gar nichts darüber wissen, was der Controller denn so zum Arbeiten braucht. Vielleicht liefert der Controller ja etwas statisches zurück und braucht weder DB noch eine View? Oder er liefert JSON/XML/... und braucht keine View? Daher ist dieses Zitat von dir vollkommen korrekt.
Bei dem folgenden Satz bin ich mir unsicher. Worein injectest du eine View-Factory? In den Router oder in den Controller?
In meiner Welt: der Router darf nichts darüber wissen, was der Controller denn so tut. Daher sollte die View-Factory weder im Router injected werden noch das Controller-Objekt dort instantiiert.
BTW - $_SESSION, $_GET, $_POST ist tatsächlich ein gutes Beispiel für ein singleton Objekt ($request), welches man herumreichen kann. Ich referenziere hiermal eine Symfony Kernkomponente: Symfony: HTTP-Foundation. Muss man in PHP also auch nicht neu erfinden.
Deine index.php (auch Front-Controller genannt) hat dann etwa folgende Aufgaben:
- DI-Container erstellen (inkl. des Request/Context-Objekts)
- Router entnehmen und starten.
Der Router hat Referenzen zu allen Controllern, die er benötigt - bereits fertig instantiiert, er muss also nicht das Controller-Objekt zusammenbauen. uswusf
Ich glaube nicht, dass wir sonderlich weit voneinander entfernt sind in unserer Ansicht. Ich vermute allerdings, dass du in C# "sauberer" entwickelst als in PHP, und ich will nur das Bewusstsein dafür schaffen, dass auch in PHP sauberer Code funktioniert (und empfehle dazu Symfony als Ausgangsbasis - viele Komponenten wie HTTP-Foundation oder auch die DependencyInjection-Komponente kann man auch standalone ohne das komplette Framework nutzen).
Viele Grüße Matti