Hi!
Aber ich kann's nicht oft genug sagen: Danke für Deine Hilfe!
Das ist mir gegenüber nicht nötig. Ich entnehme den Dank implizit aus der Art und Weise, wie auf meine Postings reagiert wird. Und da bist du ein mustergültiges Exemplar eines Probleminhabers. Vor allem der Lernwille und die Selbständigkeit beim Informieren über unbekannte Begriffe ist sehr zu loben.
Ist PhpUnit so ein Test-Framework?
Ja.
(Vorschläge natürlich sehr erwünscht): http://fsac.de/dat/selfhtml/library.zip
Aber Deine Hinweise haben mir trotzdem sehr geholfen (und ich bin froh, dass ich die neuere Version nicht hochgeladen hab - Du hättest wahrscheinlich nicht ruhig schlafen können :-) ).
Ich soll doch nur kommentieren und nicht damit arbeiten, also hab ich auch keinen Grund, mich über eventuell vorhandene Missstände aufzuregen.
Ich hab jetzt unter oben genanntem Link mal eine neue Version hochgeladen, die ich eben mal gemacht habe. [...] aber vielleicht kannst Du mir kurz sagen, ob das jetzt Dependency Injection ist, was ich verwendet habe!?
Dazu hab ich selbst nochmal nachgelesen und bin zu dem Schluss gekommen, dass wir bisher nur darüber gesprochen haben, DI _möglich_ zu machen (ebenso Testbarkeit). Ansonsten haben wir immer Objekte zu Fuß erzeugt und die irgendeinem Konstruktor in die Hand gedrückt. Einen wesentlichen Aspekt von DI haben wir ausgelassen und das ist der Teil, der eigentlich die verschiedenen Komponenten zusammenbringt. Dieser Teil ist nämlich ausgelagert, ist in der Regel konfigurationsgesteuert und läuft so ab: Ein Objekt hat zum Arbeiten eine Abhängigkeit, braucht also ein anderes Objekt. Das DI-Framework kümmert sich nun darum, ein Objekt einer passenden Klasse zu instantiieren und zu übergeben, zu injizieren. Hört sich wieder eine Runde komplexer an, und das ist auch ein Kritikpunkt daran: Was da wie zusammenspielt wird nicht einfacher zu verstehen, wenn man dazu noch in eine zusätzliche Konfigurationsdatei betrachten muss.
Solange du jetzt aber nicht auch noch von deinem Aufgabengeber aufgetragen bekommst, DI richtig zu implementieren, denke ich, es reicht auch erstmal die Light-Variante mit den selbst instantiierten Objekten und ohne DI-Framework aufzusetzen. Dessen Vorteile müssen erstmal notwendig sein, um die zusätzliche Komplexität zu rechtfertigen. Auf alle Fälle verbaust du dir den Weg nicht, wenn du gegen Interfaces statt konkreter Klassen programmierst. Das widerspricht auch nicht dem YAGNI, falls ein DI-Framework gar nicht zum Einsatz kommt, denn die Trennung und lose Kopplung ist ja auch für die Testbarkeit und Erweiterbarkeit sehr hilfreich. Doch nun zum Code.
$loadHelper = new LoadHelperIni($file);
$config = new Config();
$config->load($loadHelper);
Das (aus der test.php) sieht noch nicht nach DI aus, sondern eher nach herkömmlicher Arbeitsweise. load() will zwar keine bestimmte Klasse sondern nur irgendetwas, das das LoadHelperInterface implementiert hat, aber man braucht keine DI dazu, um die Vorteile von Interfaces nutzen zu können. Ein DI-Framework überwacht den Instantiierungsprozess und kann nur dabei die benötigten Abhängigkeiten auflösen. Beim load()-Aufruf kann das DI-Framework nichts mehr ausrichten. DI-fähig wird das Ganze, wenn du die LoadHelperInterface-Übergabe in den Konstruktor verlegst und die Config-Klasse sich selbst bedient, statt über load() angewiesen zu werden.
Jetzt noch zweimal Kleinkram bezüglich der Klasse Config:
public function load(LoadHelperInterface $helper)
{
$configs = $helper->getConfigs();
$this->add($configs);
}
Hier tät ich mir den Zwischenschritt mit $configs sparen. Abgesehen davon, dass du es DI-gerecht umschreiben wollen wirst, wird die zweite Zeile nur ein Zeichen länger als die erste ist, wenn man es direkt schachtelt.
public function load(LoadHelperInterface $helper)
{
$this->add($helper->getConfigs());
}
Alles, was man zusätzlich schreiben und lesen muss, ist Arbeit. Solange die Übersichtlichkeit nicht darunter leidet, kann man sich das ruhig sparen.
Ich weiß nicht, ob ich Konstrukte wie das folgende in diesem Thread schon kommentiert hab, deswegen jetzt vielleicht doppelt (Methode add()).
if (is_array($value)) {
$this->config[$name] = new Config($value);
} else {
$this->config[$name] = $value;
}
Geht kürzer, und meiner Meinung nach auch übersichtlicher. Ziel ist ja, dass $this->config[$name] etwas zugewiesen wird. Das wird deutlicher sichbar, wenn es einmalig und am Anfang steht und dann der Trinitätsoperator verwendet wird.
$this->config[$name] = is_array($value) ? new Config($value) : $value;
Die eine Zeile ist (mir) übersichtlich genug, kann bei Bedarf aber auch als Dreizeiler ausfallen:
$this->config[$name] = is_array($value) ?
new Config($value) :
$value;
Lo!