Der-Dennis: OOP: Design Patterns (Factory Method, Dependency Injection, ...)

0 70

OOP: Design Patterns (Factory Method, Dependency Injection, ...)

Der-Dennis
  • php
  1. 0
    Tom
    1. 0
      Der-Dennis
      1. 0
        Tom
    2. 0
      Tom
      1. 0
        Der-Dennis
    3. 0
      dedlfix
      1. 0
        Tom
        1. 0
          dedlfix
          1. 0
            Der-Dennis
            1. 0
              Der-Dennis
              1. 0
                jobo
                1. 0
                  Tom
                  1. 0
                    Der-Dennis
                    1. 0
                      Tom
                      1. 0
                        Der-Dennis
                        1. 0
                          Tom
                          1. 0
                            Der-Dennis
                            1. 0
                              Tom
                              1. 0
                                Der-Dennis
                2. 0
                  Der-Dennis
            2. 0
              Sven Rautenberg
              1. 0
                jobo
                1. 0
                  Der-Dennis
  2. 0

    Konfigurationsklassen für ein MVC-Framework

    Feldspar
    • programmiertechnik
    1. 0
      Der-Dennis
      1. 0
        Feldspar
        1. 0
          Der-Dennis
  3. 0
    dedlfix
    1. 0
      Der-Dennis
      1. 0
        dedlfix
        1. 0
          Der-Dennis
          1. 0
            dedlfix
            1. 0
              Der-Dennis
              1. 0
                dedlfix
                1. 0
                  Der-Dennis
  4. 0

    OOP: Design Patterns ... -> Zend Framework

    jobo
    1. 0
      Der-Dennis
      1. 0
        jobo
        1. 0
          Der-Dennis
          1. 0
            dedlfix
            1. 0
              jobo
  5. 0
    Sven Rautenberg
    1. 0
      jobo
      1. 1
        Sven Rautenberg
        1. 0
          jobo
          1. 0
            Der-Dennis
    2. 0
      Der-Dennis
      1. 0
        Sven Rautenberg
        1. 0
          Der-Dennis
      2. 0
        dedlfix
        1. 0
          Der-Dennis
          1. 0
            dedlfix
            1. 0
              Der-Dennis
              1. 0
                dedlfix
                1. 0
                  Der-Dennis
                  1. 0
                    dedlfix
                    1. 0
                      Der-Dennis
                      1. 0
                        dedlfix
                        1. 0
                          Der-Dennis
  6. 0

    Bin erst am Montag wieder da

    Der-Dennis
  7. 0
    hotti
    1. 0
      hotti
      1. 0
        Der-Dennis
        1. 0
          hotti
          1. 0
            Der-Dennis
            • perl
          2. 0
            dedlfix
            1. 0
              Der-Dennis
        2. 0
          hotti
          1. 0
            Der-Dennis
            • perl

Hallo zusammen!

Aufgabenstellung:
Für ein neues Projekt soll als Grundlage eine Art "Mini-MVC-Framework" entworfen werden, welches vorerst nur die wichtigsten Komponenten zum Erstellen einer Anwendung enthalten soll. Natürlich soll es auch zur Lösung zukünftiger Herausforderungen einfach erweiterbar sein.
Komponenten von bereits existierenden Frameworks oder anderen Drittanbietern sollen laut Aufgabenstellung nicht verwendet werden.
Außerdem soll dem Framework die gerade aktuellste PHP-Version (derzeit 5.3.6) zugrundegelegt und der Funktionsumfang wie Namespaces, etc., auch genutzt werden.

Einleitung:
Da das Framework von der Implementierung her natürlich in sich konstistent sein und auch in Zukunft noch den Anforderungen gerecht werden soll, stellt sich jetzt die Frage, welche Design Patterns für viele Komponenten verwendet werden sollen. Eine zum jetzigen, frühen Zeitpunkt durchdachte Wahl erspart später sicherlich viel Arbeit.

Beispiele:
Um das "Problem" zu verdeutlichen, möchte ich von einer Klasse ausgehen, die Konfigurationsdaten aus verschiedenen Quellen (z.B. INI, XML, ...) lädt und anschließend für späteren Zugriff speichert. Folgende Möglichkeiten zur Umsetzung haben wir uns bisher überlegt:

1. Einzelne Klasse
Die Klasse enthält lediglich je eine eigene Funktion für die möglichen Quellen.

2. Vererbung
Unterklasse ist beispielsweise "Ini", Oberklasse "Config". "Ini" parsed die Ini-Datei und speichert die Konfigurationen wegen der Vererbung "quasi in sich selbst". "Config" ist als abstrakt definiert, sodass nur "Ini" direkt aufgerufen werden kann. Es werden also die einzelnen Funktionen aus 1) in eine eigene Klasse ausgegliedert.

3. "Helper"-Klasse
Klasse "Ini" implementiert eine Interface "Sources". Im Konstruktor von Klasse "Config" wird der Quellen-Typ ermittelt und dementsprechend eine der Quellen-Klassen, also z.B. "Ini", aufgerufen, welche anschließend ein Array von Konfigurationsdaten zurückliefert. Dieses Array wird anschließend von "Config" gespeichert. ("Ini" erbt nicht von "Config")

4. Factory Method
Eine Mischung aus 2) und 3). Unterschied: Oberklasse "Config" besitzt eine statische Fabrik-Methode. Statt wie in 2) muss diese bemüht werden, den richtigen "Ansprechpartner" zu finden und nicht der Konstruktor. Der Konstruktor ist in diesem Fall mindestens "protected".

5. Dependency Injection (Verwendet der nun folgende Fall überhaupt dieses Pattern?)
Eine Mischung aus 3) und 4). Unterschied: Hier bestimmt der Konstruktor von "Config", welcher Quellen-Typ vorliegt und instanziiert die entsprechende Helfer-Klasse. Die Helferklasse erhält eine Referenz von "Config", in die sie mittels der Methoden von "Config" Eigenschaften speichern kann.

Überleitung:
Das sind verschiedene Möglichkeiten, die wir uns überlegt haben, an die Sache ranzugehen. Alle haben sicherlich Vor- und Nachteile und es gibt sicher auch noch andere Möglichkeiten. Wir sind etwas verwirrt!

Frage:
Also nun meine Frage an Euch: Welche Möglichkeiten haltet Ihr noch für denkbar? Was haltet Ihr von den oben genannten Möglichkeiten? Welche Vor- oder Nachteile fallen Euch ein? Was würdet Ihr ganz persönlich bevorzugen, wenn Ihr mit einem Framework arbeitet?

Wir freuen uns über alle Meinungen, Anmerkungen, Vorschläge oder was-auch-immer, was uns bei unserer Entscheidungsfindung behilflich sein könnte.
Solltet Ihr Fragen zu oben beschriebenem haben, habe ich mich unklar ausgedrückt oder etwas vergessen, so schreibt bitte einfach kurz!

Ich danke Euch im Voraus für Eure Antworten,
Dennis

Ps: Sorry, dass das wieder so ein langer Text geworden ist.

  1. Hello,

    Komponenten von bereits existierenden Frameworks oder anderen Drittanbietern sollen laut Aufgabenstellung nicht verwendet werden.

    Die BB-Klasse von Christian Seiler würde ich aber keinesfalls neu erfinden müssen ;-)

    Außerdem soll dem Framework die gerade aktuellste PHP-Version (derzeit 5.3.6) zugrundegelegt und der Funktionsumfang wie Namespaces, etc., auch genutzt werden.

    Ist die auch ohne Fehler?

    Da das Framework von der Implementierung her natürlich in sich konstistent sein und auch in Zukunft noch den Anforderungen gerecht werden soll, stellt sich jetzt die Frage, welche Design Patterns für viele Komponenten verwendet werden sollen. Eine zum jetzigen, frühen Zeitpunkt durchdachte Wahl erspart später sicherlich viel Arbeit.

    "Design Patterns" sollten eigentlich nur eine Anregung darstellen. Im Spezialfall könnte man aus den verschiedenen Kompnenten auch eine eigene Lösung zusammenbauen, die es besser trifft.

    Um das "Problem" zu verdeutlichen, möchte ich von einer Klasse ausgehen, die Konfigurationsdaten aus verschiedenen Quellen (z.B. INI, XML, ...) lädt und anschließend für späteren Zugriff speichert. Folgende Möglichkeiten zur Umsetzung haben wir uns bisher überlegt:

    1. Einzelne Klasse
      Die Klasse enthält lediglich je eine eigene Funktion für die möglichen Quellen.

    Meinst Du wirklich "Funktion" oder meinst Du "extern zugängliche Methode"?

    ...

    Liebe Grüße aus dem schönen Oberharz

    Tom vom Berg

    --
     ☻_
    /▌
    / \ Nur selber lernen macht schlau
    http://bergpost.annerschbarrich.de
    1. Hey Tom,

      erst einmal danke für Deine Antwort.

      Komponenten von bereits existierenden Frameworks oder anderen Drittanbietern sollen laut Aufgabenstellung nicht verwendet werden.

      Die BB-Klasse von Christian Seiler würde ich aber keinesfalls neu erfinden müssen ;-)

      Möchte ich auch nicht. Ich kann zur Zeit nur leider nichts daran ändern, habe aber die Hoffnung, dass wir nach den ersten "eigenen" Ansätzen noch einmal die Möglichkeit bekommen, für eine Lösung aus eigenen und fremden Komponenten zu plädieren und dies dann auch angenommen wird.

      Außerdem soll dem Framework die gerade aktuellste PHP-Version (derzeit 5.3.6) zugrundegelegt und der Funktionsumfang wie Namespaces, etc., auch genutzt werden.

      Ist die auch ohne Fehler?

      Das weiß ich leider nicht. Ich habe damit bisher noch nicht gearbeitet und werde daher auch "ins kalte Wasser" geworfen. Weißt Du etwas über eventuelle Fehler?

      Da das Framework von der Implementierung her natürlich in sich konstistent sein und auch in Zukunft noch den Anforderungen gerecht werden soll, stellt sich jetzt die Frage, welche Design Patterns für viele Komponenten verwendet werden sollen. Eine zum jetzigen, frühen Zeitpunkt durchdachte Wahl erspart später sicherlich viel Arbeit.

      "Design Patterns" sollten eigentlich nur eine Anregung darstellen. Im Spezialfall könnte man aus den verschiedenen Kompnenten auch eine eigene Lösung zusammenbauen, die es besser trifft.

      Das auf jeden Fall. Aber es gibt innerhalb eines Frameworks ja doch viele Fälle, in denen verschiedene Pattern zum gleichen Ergebnis führen. Und um genau diese geht's. Wie im zuvor genannten Beispiel.
      Grundsätzlich sollte also (natürlich nur, wenn dies sinnvoll ist) das gleiche Pattern für ähnliche Zwecke verwendet werden, damit es konsistenter und somit einfacher in der Verwendung ist.

      Um das "Problem" zu verdeutlichen, möchte ich von einer Klasse ausgehen, die Konfigurationsdaten aus verschiedenen Quellen (z.B. INI, XML, ...) lädt und anschließend für späteren Zugriff speichert. Folgende Möglichkeiten zur Umsetzung haben wir uns bisher überlegt:

      1. Einzelne Klasse
        Die Klasse enthält lediglich je eine eigene Funktion für die möglichen Quellen.

      Meinst Du wirklich "Funktion" oder meinst Du "extern zugängliche Methode"?

      Du hast natürlich recht. Ich meinte "Methode". Wobei Du mich gerade darauf bringst: Es könnte ja eine interne oder eine externe Methode sein, wobei die interne Methode dann vom Konstruktor aufgerufen würde.
      Ich müsste also Punkt 1) noch in
      a) eine interne, durch den Konstruktor aufzurufende Methode und
      b) eine öffentliche Methode
      aufteilen.

      Gruß, Dennis

      1. Hello,

        jetzt geht hier gar nix mehr?

        meine Antwort unter https://forum.selfhtml.org/?t=206131&m=1398615

        @Forumsgeister:
        und der Rest fehlt?

    2. Hello,
      Hello,

      [ich kopier das hier jetzt mal zusammen, weil die Forumssoftware spinnt. Verabschiedung und Signatur fehlen...]

      Meinst Du wirklich "Funktion" oder meinst Du "extern zugängliche Methode"?

      Du hast natürlich recht. Ich meinte "Methode". Wobei Du mich gerade darauf bringst: Es könnte ja eine interne oder eine externe Methode sein, wobei die interne Methode dann vom Konstruktor aufgerufen würde.
      Ich müsste also Punkt 1) noch in
      a) eine interne, durch den Konstruktor aufzurufende Methode und
      b) eine öffentliche Methode
      aufteilen.

      Und jetzt habe ich vor lauter Forumsbug vergessen, was ich eigentlich schreiben wollte  :-|

      Achso: Durch wen die Methode aufgerufen werden muss, ist noch gar nicht klar. Ob da der Konstruktor zuständig ist, oder Du eine "späte Bindung" benötigst (usw.), entscheidet die Aufgabenstellung.

      Liebe Grüße aus dem schönen Oberharz

      Tom vom Berg

      --
       ☻_
      /▌
      / \ Nur selber lernen macht schlau
      http://bergpost.annerschbarrich.de
      1. Hey Tom,

        [...] Durch wen die Methode aufgerufen werden muss, ist noch gar nicht klar. Ob da der Konstruktor zuständig ist, oder Du eine "späte Bindung" benötigst (usw.), entscheidet die Aufgabenstellung.

        Späte Bindung ist sicherlich ein Thema, auf das wir später noch achten müssen. Wenn wir das Beispiel der Konfigurationsklasse nehmen, brauchen wir das zur Zeit aber noch nicht. Die Daten sollen in jedem Fall geladen werden und werden auch in jedem Fall gebraucht.
        Mir fällt dabei aber gerade ein: Worauf wir auf jeden Fall jetzt schon achten müssen ist Möglichkeit für späteres cachen der Daten.

        Gruß und danke für die Erinnerung,
        Dennis

    3. Hi!

      Außerdem soll dem Framework die gerade aktuellste PHP-Version (derzeit 5.3.6) zugrundegelegt und der Funktionsumfang wie Namespaces, etc., auch genutzt werden.
      Ist die auch ohne Fehler?

      Definiere "ohne Fehler".

      Lo!

      1. Hello,

        Außerdem soll dem Framework die gerade aktuellste PHP-Version (derzeit 5.3.6) zugrundegelegt und der Funktionsumfang wie Namespaces, etc., auch genutzt werden.
        Ist die auch ohne Fehler?

        Definiere "ohne Fehler".

        Jaaaaa. Du wirst hier immer recht behalten. Gänzlich fehlerfreie Software wird vermutlich noch nie jemand produziert haben. Aber gerade mit "wir benutzen die neueste Version" habe ich schlechte Erfahrungen gemacht. Wobei die Version 5.3 ja nun schon nicht mehr so neu ist und 5.3.6 darauf schließen lässt, dass eben schon sechsmal garvierende Fehler ausgebügelt wurden.

        Ich würde mich aber nicht trauen, ein Projekt auf 5.4.0 aufzusetzen...

        Außerdem muss man davon ausgehen, dass viele, viele Installationen noch mit 5.2.x fahren und dies auch noch eine Weile fortsetzen müssen.

        Außerdem sollte man, wenn man auf die Funktionalität einer bestimmten Version angewiesen ist, diese auch abprüfen und die Arbeit verweigern, wenn sie nicht vorhanden ist.

        Das ist aber mMn Microsoftismus. Hier regt eine Software den Verkauf der anderen an...

        Liebe Grüße aus dem schönen Oberharz

        Tom vom Berg

        --
         ☻_
        /▌
        / \ Nur selber lernen macht schlau
        http://bergpost.annerschbarrich.de
        1. Hi!

          Ich würde mich aber nicht trauen, ein Projekt auf 5.4.0 aufzusetzen...
          Außerdem muss man davon ausgehen, dass viele, viele Installationen noch mit 5.2.x fahren und dies auch noch eine Weile fortsetzen müssen.

          Mir scheint es hier um ein akademischens Projekt zu gehen. Es sollen wohl eher aktuelle Programmierparadigmen geübt werden denn Lauffähigkeit auf alten Installationen sichergestellt. In dem Fall kommt es dann auch nicht so sehr auf Sicherheitsmängel an, vor allem dann nicht, wenn das Ergebnis nur im Labor laufen soll.

          Und selbst wenn man anfängt, ein Projekt mit einer 0er oder Beta-Version aufzusetzen, in der sich sich später funktionale Änderungen ergeben, so kann man daraus immer noch lernen, sein eigenes Zeug testbar zu schreiben, so dass solche Änderungen einfach auffallen.

          Lo!

          1. Hey Tom, hey dedlfix,

            Ich würde mich aber nicht trauen, ein Projekt auf 5.4.0 aufzusetzen...
            Außerdem muss man davon ausgehen, dass viele, viele Installationen noch mit 5.2.x fahren und dies auch noch eine Weile fortsetzen müssen.

            Mir scheint es hier um ein akademischens Projekt zu gehen. Es sollen wohl eher aktuelle Programmierparadigmen geübt werden denn Lauffähigkeit auf alten Installationen sichergestellt. In dem Fall kommt es dann auch nicht so sehr auf Sicherheitsmängel an, vor allem dann nicht, wenn das Ergebnis nur im Labor laufen soll.

            Um es etwas verständlicher zu machen, worum es geht: Ich arbeite als Hiwi an einem Uni-Institut. Falls es interessiert: Ich studiere nicht Informatik oder etwas vergleichbares, sondern Maschinenbau und bin somit was Informatik-Fragen angeht kein Experte.
            Im Bereich Qualitätssicherung gibt es viele EDV-Anwendungen, die zu diesem Zweck an dem Institut entwickelt wurden. Darunter auch einige PHP-Anwendungen.
            Alle diese PHP-Anwendungen funktionieren völlig verschieden. Das eine Programm verwendet Framework A, das andere Framework B und ein anderes gar kein Framework.
            Um in Zukunft eine einheitliche Basis zu haben, soll nun ein "Institut-eigenes" Framework entworfen werden.
            Da auch "den Chefs" bekannt ist, wie lang so etwas dauern kann, soll die neueste Version zugrunde gelegt werden.

            Gruß, Dennis

            1. Und noch eine kleine Ergänzung:
              Da es sich um ein Uni-Projekt handelt, wird natürlich sehr viel Wert auf wissenschaftliche Vorgehensweise gelegt. Daher auch die Auseinandersetzung mit den verschiedenen Paradigmen, etc., von denen ich bisher noch nicht viel gehört habe.

              Gruß, Dennis

              1. Hallo,

                Und noch eine kleine Ergänzung:
                Da es sich um ein Uni-Projekt handelt, wird natürlich sehr viel Wert auf wissenschaftliche Vorgehensweise gelegt. Daher auch die Auseinandersetzung mit den verschiedenen Paradigmen, etc., von denen ich bisher noch nicht viel gehört habe.

                Vergleiche ZF mit ZF2.0 und den anderen gängigen PHP-Frameworks (Cake, Symfony, CodeIgniter, Yii etc.pp.). Das wäre für mich wissenschaftlich. Da kommen dir auch alle Paradigmen unter.

                http://www.phpframeworks.com/top-10-php-frameworks/

                http://www.phpframeworks.com/

                http://en.wikipedia.org/wiki/Comparison_of_Web_application_frameworks#PHP

                Gruß

                jobo

                1. Hello,

                  Vergleiche ZF mit ZF2.0 und den anderen gängigen PHP-Frameworks (Cake, Symfony, CodeIgniter, Yii etc.pp.). Das wäre für mich wissenschaftlich. Da kommen dir auch alle Paradigmen unter.

                  http://www.phpframeworks.com/top-10-php-frameworks/

                  http://www.phpframeworks.com/

                  http://en.wikipedia.org/wiki/Comparison_of_Web_application_frameworks#PHP

                  Das ist eigentlich eine gute Idee und sollte vom Institut unterstützt werden!

                  Ich konnte jetzt auf die Schnelle keine vernünftige Übersicht dieser Art finden.

                  Die Fein-Ergebnisse und daraus entstehende Empfehlungen könnten später sogar verkauft werden und man könnte dann aus allen Frameworks und den gewonnenen Erkenntnissen die besten Ideen zu einem neuen zusammenpappen - sofern sie überhaupt zusammenpassen.

                  Liebe Grüße aus dem schönen Oberharz

                  Tom vom Berg

                  --
                   ☻_
                  /▌
                  / \ Nur selber lernen macht schlau
                  http://bergpost.annerschbarrich.de
                  1. Hey Tom,

                    Vergleiche ZF mit ZF2.0 und den anderen gängigen PHP-Frameworks (Cake, Symfony, CodeIgniter, Yii etc.pp.). Das wäre für mich wissenschaftlich. Da kommen dir auch alle Paradigmen unter.

                    Das ist eigentlich eine gute Idee und sollte vom Institut unterstützt werden!

                    willst Du nicht mal vorbeikommen und denen das erklären, dass das sinnvoll wäre? ;-)

                    Gruß, Dennis

                    1. Hello,

                      Vergleiche ZF mit ZF2.0 und den anderen gängigen PHP-Frameworks (Cake, Symfony, CodeIgniter, Yii etc.pp.). Das wäre für mich wissenschaftlich. Da kommen dir auch alle Paradigmen unter.

                      Das ist eigentlich eine gute Idee und sollte vom Institut unterstützt werden!

                      willst Du nicht mal vorbeikommen und denen das erklären, dass das sinnvoll wäre? ;-)

                      Hast Du es denn selber schon versucht? Bei Verdienstmöglichkeiten zucken die Institutsleiter meistens.

                      Und auch, wenn sie es nicht unterstützen wollen, könntest DU doch als Abfallprodukt der Aufgabe eine (erweiterungsfähige) Matrix entwickeln, mit deren Hilfe man nachher die Frameworks bewerten könnte. Dann hättest Du damit eine Superidee für eine vielbesuchte Webseite.

                      Liebe Grüße aus dem schönen Oberharz

                      Tom vom Berg

                      --
                       ☻_
                      /▌
                      / \ Nur selber lernen macht schlau
                      http://bergpost.annerschbarrich.de
                      1. Hey Tom,

                        willst Du nicht mal vorbeikommen und denen das erklären, dass das sinnvoll wäre? ;-)

                        Hast Du es denn selber schon versucht?

                        ja, mehrfach, mittlerweile schon seit über einem Monat (man, hätte man in der Zeit schon _wirklich_ produktiv sein können). Und nicht nur ich allein.

                        Bei Verdienstmöglichkeiten zucken die Institutsleiter meistens.

                        Das kann ich mir gut vorstellen. Aber im Allgemeinen hört ein "Prof" nicht auf den "Hiwi". Anders: "Hiwi" kann "Prof" gar nicht sprechen. Da sind "zig Vermittler" dazwischen, die dann entweder "hat der so gesagt" sagen oder aber "ich will das jetzt aber so". Das dürfte aber nicht nur im universitären Bereich so sein...

                        Und auch, wenn sie es nicht unterstützen wollen, könntest DU doch als Abfallprodukt der Aufgabe eine (erweiterungsfähige) Matrix entwickeln, mit deren Hilfe man nachher die Frameworks bewerten könnte. [...]

                        Damit könnte ich mich wirklich mal beschäftigen. Ich glaube aber,um das vernünftig zu machen, müsste man ein paar mehr Leute zusammenbringen. Hättest Du Lust?

                        Gruß,
                        Dennis

                        1. Hello,

                          Und auch, wenn sie es nicht unterstützen wollen, könntest DU doch als Abfallprodukt der Aufgabe eine (erweiterungsfähige) Matrix entwickeln, mit deren Hilfe man nachher die Frameworks bewerten könnte. [...]

                          Damit könnte ich mich wirklich mal beschäftigen. Ich glaube aber,um das vernünftig zu machen, müsste man ein paar mehr Leute zusammenbringen. Hättest Du Lust?

                          Naja, ob das nun unbedingt Spaß macht, weiß ich nicht. Aber nützlich wäre es schon, wenn auch nur für die eigene Übung.

                          Liebe Grüße aus dem schönen Oberharz

                          Tom vom Berg

                          --
                           ☻_
                          /▌
                          / \ Nur selber lernen macht schlau
                          http://bergpost.annerschbarrich.de
                          1. Hey Tom,

                            Naja, ob das nun unbedingt Spaß macht, weiß ich nicht. Aber nützlich wäre es schon, wenn auch nur für die eigene Übung.

                            Spaß macht das sicherlich nicht wirklich. Da ich mich jetzt aber wohl oder übel etwas mehr damit beschäftigen muss, werde ich mir nebenbei mal ein paar Notizen machen. Je nachdem, wie umfangreich das wird, kann man damit ja vielleicht später wirklich mal was anfangen.

                            Gruß, Dennis

                            1. Hello,

                              Naja, ob das nun unbedingt Spaß macht, weiß ich nicht. Aber nützlich wäre es schon, wenn auch nur für die eigene Übung.

                              Spaß macht das sicherlich nicht wirklich. Da ich mich jetzt aber wohl oder übel etwas mehr damit beschäftigen muss, werde ich mir nebenbei mal ein paar Notizen machen. Je nachdem, wie umfangreich das wird, kann man damit ja vielleicht später wirklich mal was anfangen.

                              Wenn Du es ins Netz stellen würdest (vielleicht auf einer geschlossenen Seite), dann würde ich gerne mitlesen und ggf. auch etwas dazu beitragen. Ich bin ja als OOP-Sinn-Bezweifler bekannt hier (zumindest bei Scriptsprachen), umso intensiver müsste ich recherchieren, um dann mal etwas dazu sagen zu mögen...

                              Liebe Grüße aus dem schönen Oberharz

                              Tom vom Berg

                              --
                               ☻_
                              /▌
                              / \ Nur selber lernen macht schlau
                              http://bergpost.annerschbarrich.de
                              1. Hey Tom,

                                Wenn Du es ins Netz stellen würdest (vielleicht auf einer geschlossenen Seite), dann würde ich gerne mitlesen und ggf. auch etwas dazu beitragen. Ich bin ja als OOP-Sinn-Bezweifler bekannt hier (zumindest bei Scriptsprachen), umso intensiver müsste ich recherchieren, um dann mal etwas dazu sagen zu mögen...

                                ich schau mal, wie das in den nächsten zwei, drei Wochen so läuft und meld mich dann bei Dir.

                                Gruß, Dennis

                2. Hey jobo,

                  Vergleiche ZF mit ZF2.0 und den anderen gängigen PHP-Frameworks (Cake, Symfony, CodeIgniter, Yii etc.pp.). Das wäre für mich wissenschaftlich. Da kommen dir auch alle Paradigmen unter.

                  http://www.phpframeworks.com/top-10-php-frameworks/

                  http://www.phpframeworks.com/

                  http://en.wikipedia.org/wiki/Comparison_of_Web_application_frameworks#PHP

                  danke für die Links! Aber bis ich da durch bin, wird's wohl etwas dauern... :-)

                  Gruß, Dennis

            2. Moin!

              Im Bereich Qualitätssicherung gibt es viele EDV-Anwendungen, die zu diesem Zweck an dem Institut entwickelt wurden. Darunter auch einige PHP-Anwendungen.
              Alle diese PHP-Anwendungen funktionieren völlig verschieden. Das eine Programm verwendet Framework A, das andere Framework B und ein anderes gar kein Framework.
              Um in Zukunft eine einheitliche Basis zu haben, soll nun ein "Institut-eigenes" Framework entworfen werden.

              Falscher Ansatz!

              In der PHP-Welt existieren ausreichend Frameworks, die jeweils von einer großen Community unterstützt und weiterentwickelt werden. Alle Open-Source.

              Warum wollt ihr Aufwand in die Entwicklung eines eigenen Frameworks stecken, und dann nochmal Aufwand in die Umstellung aller Applikationen auf dieses Framework, was dann wieder die ganzen Schwächen und Noch-nicht-implementiert-Lücken dieses Frameworks aufdeckt, wenn man die Entwicklungzeit des Frameworks durch Nutzung existierender Software abkürzen und sich somit direkt mit der Umstellung der Software beschäftigen kann?

              Idealerweise wird auf DAS Framework umgestellt, welches von der Mehrheit der existierenden Software benutzt wird, wobei man als Startübung die Aktualisierung auf die aktuellste Version dieses Frameworks einplanen sollte.

              Ihr könnt natürlich auch einfach Zend Framework nehmen. ;)

              - Sven Rautenberg

              1. Hallo,

                Ihr könnt natürlich auch einfach Zend Framework nehmen. ;)

                Ja, in die Richtung dachte ich ja seiner Zeit auch schon mal (;-).

                Gruß

                jobo

                1. Hey Sven, hey jobo,

                  Ihr könnt natürlich auch einfach Zend Framework nehmen. ;)

                  Ja, in die Richtung dachte ich ja seiner Zeit auch schon mal (;-).

                  wie gesagt, mir wäre das so auch am liebsten.

                  Ich hatte ja in älteren Posts schonmal gesagt, ich wolle ein eigenes Framework auf die Beine stellen.
                  Nach Euren Antworten und ein bisschen rumexperementieren hab ich's aber aufgegeben, weil's für mich keinen Sinn macht. Und seitdem arbeite ich (sehr zufrieden) mit dem ZF.

                  Und gerade deshalb hätte ich das auch jetzt gerne eingesetzt (spart Arbeit, kenn' ich ja schon :-) ). Aber es ist nunmal der ausdrückliche Wunsch der "Ober-Aufseher". Und solange die sich nicht erweichen lassen muss ich damit leben.

                  Gruß, Dennis

  2. G'bitte, soviel Architekturastronautismus habe ich ja selten seit der großen Javaschwemme auf einem Haufen gesehen. Selbst PHP-Frickler sind nicht davor gefeit, wenn die praktische Erfahrung aus dem Echten Leben™ fehlt.

    Die korrekte Antwort lautet: in deinem MVC-Framework haben einbaute Konfigurationsklassen nichts verloren. Lagere sie aus und melde sie fürs Packaging als Abhängigkeit.

    Beim Design der Konfigurationsklassen orientiere dich an Config::JFDI (überlässt dem Benutzer die Wahl der Mittel, überlagert örtliche Konfiguration in die Grundkonfiguration) und Config::Any (Systemer werden dir an die Gurgel springen, wenn du nur Ini anbietest, konzentriere dich zunächst auf die ausdrucksstarken hierarchischen Formate, videlicet General). Dabei kommst du mit Rollen (in PHP nicht möglich) oder Einfachvererbung aus, und möchtest vielleicht Callbacks exponieren. Das ist keine Raketenchirurgie.

    1. Hey Feldspar,

      G'bitte, soviel Architekturastronautismus habe ich ja selten seit der großen Javaschwemme auf einem Haufen gesehen. Selbst PHP-Frickler sind nicht davor gefeit, wenn die praktische Erfahrung aus dem Echten Leben™ fehlt.

      ich bin auch ganz erstaunt, wie viele Gedanken man sich darüber machen kann. Aber da es ein Projekt für ein Uni-Institut ist, müssen wir uns zum ersten Mal vorher (wissenschaftliche) Gedanken drüber machen, was wir später implementieren wollen. Bis vor ein paar Tagen habe ich den Großteil der Begriffe wie Dependency Injection noch nie gehört, obwohl ich es wohl schonmal verwendet habe.

      Die korrekte Antwort lautet: in deinem MVC-Framework haben einbaute Konfigurationsklassen nichts verloren. Lagere sie aus und melde sie fürs Packaging als Abhängigkeit.

      Irgendwie versteh ich das grad nicht ganz. Die Konfigurationen sollen schon in ein Modul bzw. Package eingefügt werden. Aber das ist dann doch Teil des Frameworks!?

      Beim Design der Konfigurationsklassen orientiere dich an Config::JFDI (überlässt dem Benutzer die Wahl der Mittel, überlagert örtliche Konfiguration in die Grundkonfiguration) und Config::Any (Systemer werden dir an die Gurgel springen, wenn du nur Ini anbietest, konzentriere dich zunächst auf die ausdrucksstarken hierarchischen Formate, videlicet General). Dabei kommst du mit Rollen (in PHP nicht möglich) oder Einfachvererbung aus, und möchtest vielleicht Callbacks exponieren.

      Schaue ich mir an! Danke!

      Das ist keine Raketenchirurgie.

      Sehr schön :-)

      Gruß und danke für Deine Antwort,
      Dennis

      1. Lagere sie aus und melde sie fürs Packaging als Abhängigkeit.
        Irgendwie versteh ich das grad nicht ganz. Die Konfigurationen sollen schon in ein Modul bzw. Package eingefügt werden. Aber das ist dann doch Teil des Frameworks!?

        Ne, ein separates Package. Abhängigkeiten werden in die Metadatei geschrieben.

        1. Lagere sie aus und melde sie fürs Packaging als Abhängigkeit.
          Irgendwie versteh ich das grad nicht ganz. Die Konfigurationen sollen schon in ein Modul bzw. Package eingefügt werden. Aber das ist dann doch Teil des Frameworks!?

          Ne, ein separates Package. Abhängigkeiten werden in die Metadatei geschrieben.

          Jetzt weiß ich was Du meinst. Danke für die Links! Aber auch da muss ich mich erstmal einlesen, weil ich mich damit bisher noch nicht beschäftigt hab.

          Gruß, Dennis

  3. Hi!

    Da das Framework von der Implementierung her natürlich in sich konstistent sein und auch in Zukunft noch den Anforderungen gerecht werden soll, stellt sich jetzt die Frage, welche Design Patterns für viele Komponenten verwendet werden sollen. Eine zum jetzigen, frühen Zeitpunkt durchdachte Wahl erspart später sicherlich viel Arbeit.

    Durchdacht für welche konkreten Einsatzzwecke? Die Aufgabenstellung ist ja recht allgemein formuliert, also kann man auch nur eine allgemeine Regel wie zum Beispiel die 80/20 heranziehen. Nur sollte man beachten, dass die 20 nicht heißt, 20% der potentiellen Anwendungsfälle unmöglich zu machen, indem man genau die 80% Fälle abdeckt und den Rest verhindert. Besser ist, 80% abzudecken und für den Rest erweiterbar bleiben - also Plugins vorsehen, "final" und andere abschließenden Dinge sehr gut bedenken. Ich kann mich nicht erinnern, final/sealed schon verwendet zu haben, bin aber schon mehrfach an einer Erweiterungsmöglichkeit gescheitert, weil Framework-Konponenten sich derart abgeschlossen und die eigentlich interessante Arbeit in interne Methoden versteckt hatten, dass ich sie gleich neu schreiben hätte müssen. (War kein PHP, also kein offener Quelltext, aber mit Reflection konnte man sich den inneren Aufbau anschauen.)

    Um das "Problem" zu verdeutlichen, möchte ich von einer Klasse ausgehen, die Konfigurationsdaten aus verschiedenen Quellen (z.B. INI, XML, ...) lädt und anschließend für späteren Zugriff speichert. Folgende Möglichkeiten zur Umsetzung haben wir uns bisher überlegt:

    Wichtig ist nicht nur, welche Entwurfsmuster eingesetzt werden, sondern dass man sich auch ein Bild macht, welche Arten der Speicherung es gibt und wie kann man die mit einer sehr allgemeinen Datenstruktur flexibel nachbilden. XML ist vielleicht das Format mit den komplexesten Möglichkeiten. Es gibt Elemente mit Inhalt und nebenher lassen sich noch Attribute in den Elemente unterbingen. Verschachtlungen bis zum Umfallen und Namespaces sind weitere Möglichkeiten. Selbst .ini ist nicht nur Name-Value. Es lässt sich durch Sections gruppieren und über Benennungskonventionen nahezu beliebig schachteln. Wenn

    [foo]
      a = ...
      b = ...

    nicht reicht, erweitert man es eben auf solch eine Art:

    [foo]
      bar.a = ...
      bar.b = ...
      qux.a = ...
      qux.b = ...

    Wenn man nun mit einer Config-Klasse daherkommt, die nur Name-Value-Pärchen unterstützt, hat man vermutlich noch nicht mal die 80% erreicht.

    1. Einzelne Klasse
      Die Klasse enthält lediglich je eine eigene Funktion für die möglichen Quellen.

    Quick and dirty. Lässt sich eigentlich nur über Code-Hinzufügen erweitern. Erben und neue Quellen-Methode hinzufügen geht auch, aber dazu muss der Aufruf der Quellen-Methode per Hand erfolgen oder deren Name konfigurierbar sein. Sicherlich effektiv, aber künstlerisch nicht besonders wertvoll. Scheitert, wenn der Original-Code wegen OpCode-Compilern und anderen Verschleierungsmethoden nicht geändert werden kann.

    1. Vererbung
      Unterklasse ist beispielsweise "Ini", Oberklasse "Config". "Ini" parsed die Ini-Datei und speichert die Konfigurationen wegen der Vererbung "quasi in sich selbst". "Config" ist als abstrakt definiert, sodass nur "Ini" direkt aufgerufen werden kann. Es werden also die einzelnen Funktionen aus 1) in eine eigene Klasse ausgegliedert.

    Schon besser im Hinblick auf Erweiterbarkeit und Trennung nach einzelnen Speicherarten. Welche der Unterklassen verwendet werden soll, muss fest im Code stehen oder durch Instantiierung über Stringvariable statt Klassennamen erfolgen (falls man konfigurieren können muss, welche Konfigurationsklasse verwendet werden soll). Für die Instantiierung über Stringvariable scheint sich kein Begriff etabliert zu haben, wie bei variable Variablen. Variable Klassen könnte man das nennen.

    1. "Helper"-Klasse
      Klasse "Ini" implementiert eine Interface "Sources". Im Konstruktor von Klasse "Config" wird der Quellen-Typ ermittelt und dementsprechend eine der Quellen-Klassen, also z.B. "Ini", aufgerufen, welche anschließend ein Array von Konfigurationsdaten zurückliefert. Dieses Array wird anschließend von "Config" gespeichert. ("Ini" erbt nicht von "Config")

    Sieht fast nach DI aus. Nur dass du wohl daran denkst, dem Konstruktor einen Wert zu übergeben, über den man die Quellen-Klasse instantiieren kann, statt eines Objekts einer Quellenklasse selbst. Wenn nicht mit variablen Klassen gearbeitet werden soll, ist man hier auch auf einen vordefinierten Vorrat beschränkt.

    1. Factory Method
      Eine Mischung aus 2) und 3). Unterschied: Oberklasse "Config" besitzt eine statische Fabrik-Methode. Statt wie in 2) muss diese bemüht werden, den richtigen "Ansprechpartner" zu finden und nicht der Konstruktor. Der Konstruktor ist in diesem Fall mindestens "protected".

    Das ist eher eine Ergänzung zu 2 oder 3. ie Factory legt fest, was verwendet wird. Ob das nun eine Helper- oder eine geerbte Klasse ist, ist dabei nebensächlich. Jedenfalls ist das nicht wirklich testbar - falls das notwendig sein sollte.

    1. Dependency Injection (Verwendet der nun folgende Fall überhaupt dieses Pattern?)
      Eine Mischung aus 3) und 4). Unterschied: Hier bestimmt der Konstruktor von "Config", welcher Quellen-Typ vorliegt und instanziiert die entsprechende Helfer-Klasse. Die Helferklasse erhält eine Referenz von "Config", in die sie mittels der Methoden von "Config" Eigenschaften speichern kann.

    Nach meinem Wissen über DI bekommt der Konstruktor bereits eine Instanz der Helperklasse übergeben. Config kann diese dann "melken". Zur Not kann es einen Default-Fall geben, wenn kein Helper-Objekt übergeben wird, erstellt sich der Config-Konstruktor eins selbst. Der Name der physikalischen Konfig-Datenhaltung müsste dann über eine Konvention ermittelt werden.

    So wie du das beschreibst, ist (mir) das zu sehr ineinander verzahnt. Dein Konstruktor sieht wie eine Factory aus. Und statt dass Config einfach die Quellen-Objekt-Methoden verwendet, um sich zu füllen, muss sich Config dem von ihm selbst erstellten Quellen-Objekt regelrecht aufdrängen, auf dass es es befülle. Damit machst du nur das Testen von Config- und Quellen-Klassen schwer, weil stets ein (Mock-)Objekt der jeweils anderen Klasse benötigt wird.

    Muss das ganze TDD-fähig sein? Muss man Mock-Objekte übergeben können? Aber auch ansonsten sieht mir das am saubersten aus, weil hier nicht mit variablen Klassen hantiert werden muss, um flexibel zu sein.

    Das sind verschiedene Möglichkeiten, die wir uns überlegt haben, an die Sache ranzugehen. Alle haben sicherlich Vor- und Nachteile und es gibt sicher auch noch andere Möglichkeiten. Wir sind etwas verwirrt!

    Wenn du noch mehr Möglichkeiten kennenlernst, wird das Bild nicht unbedingt klarer.

    Also nun meine Frage an Euch: Welche Möglichkeiten haltet Ihr noch für denkbar?

    Mit parse_ini_file() und SimpleXML kommt man auch an Konfigurationsdaten ran, aber so einfach und unflexibel willst du es ja nicht haben :-) Komplexer und komplizierter geht immer. Zum Beispiel könnte man statt eines (verschachtelten) Arrays in der Config-Klasse weiteren Klassen vorsehen, die im einfachsten Fall einen Wert aber auch andere individuelle Strukturen enthalten können.

    Was würdet Ihr ganz persönlich bevorzugen, wenn Ihr mit einem Framework arbeitet?

    Zu allgemein gefragt kann ich da nur zu allgemein antworten. Meine aktuellen Bedürfnisse muss es erfüllen können, notfalls durch individuelle Erweiterbarkeit.

    Wir freuen uns über alle Meinungen, Anmerkungen, Vorschläge oder was-auch-immer, was uns bei unserer Entscheidungsfindung behilflich sein könnte.

    Schamlos bei anderen abschauen, wie die es gelöst haben, ausprobieren, Erfahrungen sammeln, aus deren Fehlern lernen, was bei anderen zu komplex geraten ist, auf einfache(re) Weise nachbauen, dann selbst um so viel benötigte Funktionalität erweitern, biss es mindestens genauso komplex und unüberschaubar geworden ist, ...

    Ps: Sorry, dass das wieder so ein langer Text geworden ist.
    Solltet Ihr Fragen zu oben beschriebenem haben, habe ich mich unklar ausgedrückt oder etwas vergessen, so schreibt bitte einfach kurz!

    Nö, ich kann auch "lang".

    Lo!

    1. Hey dedlfix,

      ich kann mich wieder einmal nur herzlich für Deine aufschlussreiche Antwort bedanken!

      Eine zum jetzigen, frühen Zeitpunkt durchdachte Wahl erspart später sicherlich viel Arbeit.

      Durchdacht für welche konkreten Einsatzzwecke?

      Da hab ich mich wieder sehr schwammig ausgedrückt. Das Framework sollte natürlich insgesamt durchdacht sein. An dieser Stelle soll es jedoch erstmal darum gehen, welcher Stil allgemein verwendet werden soll - natürlich nur, wenn es sinnvoll ist.
      Als Beispiel: Ein Konfigurationsobjekt ist vergleichbar mit einer Registry. Damit nachher auch "vernünftig" damit gearbeitet werden kann, sollen jetzt zum Beispiel Config und Registry auf gleichem Wege zugänglich sein. Also beispielsweise über eine Factory-Method und nicht eins über Factory und das andere über DI und noch ein anderes kann vielleicht nur über die Unterklasse angesprochen werden.
      Das meinten wir hier mit "Konsistenz".

      Die Aufgabenstellung ist ja recht allgemein formuliert,

      Ja, leider.

      also kann man auch nur eine allgemeine Regel wie zum Beispiel die 80/20 heranziehen.

      Das ist schon mal super. So haben wir jetzt mal eine "ungefähre Hausnummer".

      [...] Besser ist, 80% abzudecken und für den Rest erweiterbar bleiben - also Plugins vorsehen, "final" und andere abschließenden Dinge sehr gut bedenken. [...]

      Das ist tatsächlich ein Problem. Einer bei uns im Team verwendet fast nur "private" und "final", ein anderer ausschließlich "public". Ich persönlich verwende oft "protected". Gut, dass Du das ansprichst: Da müssen wir mal klare Regeln finden.

      [dedlfix' Beschreibung möglicher Datenhaltung und Verschachtelungen in Konfigurations-Objekten, siehe vorheriges Posting]

      Darüber haben wir uns auch schon Gedanken gemacht und versuchen, das auch umzusetzen. Bei der Ini-Variante werden wir wohl das von Dir beschriebene Verfahren mit dem Punkt als Trennzeichen für Verschachtelungen verwenden.

      1. Einzelne Klasse [...]

      Quick and dirty. Lässt sich eigentlich nur über Code-Hinzufügen erweitern. Erben und neue Quellen-Methode hinzufügen geht auch, aber dazu muss der Aufruf der Quellen-Methode per Hand erfolgen oder deren Name konfigurierbar sein. Sicherlich effektiv, aber künstlerisch nicht besonders wertvoll.

      Das kam auch bei unseren Gesprächen heraus. Danke für die Bestätigung!

      Scheitert, wenn der Original-Code wegen OpCode-Compilern [...] nicht geändert werden kann.

      Das verstehe ich leider nicht. Wie meinst Du das mit den OpCode-Compilern? In welcher Form spielen die eine Rolle für die Erweiterung des Original-Codes?

      1. Vererbung [...]

      Schon besser im Hinblick auf Erweiterbarkeit und Trennung nach einzelnen Speicherarten. Welche der Unterklassen verwendet werden soll, muss fest im Code stehen oder durch Instantiierung über Stringvariable statt Klassennamen erfolgen (falls man konfigurieren können muss, welche Konfigurationsklasse verwendet werden soll).

      Das sollte man auf jeden Fall können. Also wohl auch nicht gerade die beste Wahl, was die Erweiterbarkeit angeht.

      Für die Instantiierung über Stringvariable scheint sich kein Begriff etabliert zu haben, wie bei variable Variablen. Variable Klassen könnte man das nennen.

      Jetzt hat sich, zumindest bei uns, der Begriff "Variable Klasse" etabliert. Super!

      1. "Helper"-Klasse [...]

      Sieht fast nach DI aus. Nur dass du wohl daran denkst, dem Konstruktor einen Wert zu übergeben, über den man die Quellen-Klasse instantiieren kann, statt eines Objekts einer Quellenklasse selbst.

      Genau das war die Idee, auch wenn ich mich wieder etwas schwierig ausgedrückt habe.

      Wenn nicht mit variablen Klassen gearbeitet werden soll, ist man hier auch auf einen vordefinierten Vorrat beschränkt.

      Stimmt, die vorgegebenen Möglichkeiten sind wohl auch hier das Problem. "Variable Klassen" sollten nicht verwendet werden.

      1. Factory Method [...]

      Das ist eher eine Ergänzung zu 2 oder 3. ie Factory legt fest, was verwendet wird. Ob das nun eine Helper- oder eine geerbte Klasse ist, ist dabei nebensächlich. Jedenfalls ist das nicht wirklich testbar - falls das notwendig sein sollte.

      Das mit der Testbarkeit ist ein guter Punkt! Den haben wir im Moment etwas aus den Augen verloren, wäre aber sehr wichtig. Warum erschwert eine Factory das Testen?

      1. Dependency Injection [...]

      Nach meinem Wissen über DI bekommt der Konstruktor bereits eine Instanz der Helperklasse übergeben. Config kann diese dann "melken". Zur Not kann es einen Default-Fall geben, wenn kein Helper-Objekt übergeben wird, erstellt sich der Config-Konstruktor eins selbst. Der Name der physikalischen Konfig-Datenhaltung müsste dann über eine Konvention ermittelt werden.

      Also haben wir uns, wie zuvor beschrieben, sozusagen eine "Anti-DI" ausgedacht?
      Anti-DI: Oberklasse übergibt sich selbst an Helferklasse
      DI: Oberklasse erhält Helferklasse

      Dann würde DI ja richtig Sinn machen :-) und erscheint mir vorerst als "beste Wahl" für solche Anwendungszwecke.

      So wie du das beschreibst, ist (mir) das zu sehr ineinander verzahnt.

      Mir auch... Deshalb ja die Frage.

      Dein Konstruktor sieht wie eine Factory aus. Und statt dass Config einfach die Quellen-Objekt-Methoden verwendet, um sich zu füllen, muss sich Config dem von ihm selbst erstellten Quellen-Objekt regelrecht aufdrängen, auf dass es es befülle. Damit machst du nur das Testen von Config- und Quellen-Klassen schwer, weil stets ein (Mock-)Objekt der jeweils anderen Klasse benötigt wird.

      Du bringst es auf den Punkt, worüber wir uns schon Stunden unterhalten haben.

      Muss das ganze TDD-fähig sein? [...]

      Ich wusste bis gerade nicht, was TDD bedeutet (für alle Unwissenden wie mich: Testgetriebene Entwicklung). Ja, so wollen wir es machen! Und jetzt haben wir auch endlich einen Namen dafür :-)

      Das sind verschiedene Möglichkeiten, die wir uns überlegt haben, an die Sache ranzugehen. Alle haben sicherlich Vor- und Nachteile und es gibt sicher auch noch andere Möglichkeiten. Wir sind etwas verwirrt!

      Wenn du noch mehr Möglichkeiten kennenlernst, wird das Bild nicht unbedingt klarer.

      Das nicht. Aber vielleicht ist ja die ultimative Umsetzung dabei ;-)

      Also nun meine Frage an Euch: Welche Möglichkeiten haltet Ihr noch für denkbar?

      Mit parse_ini_file() und SimpleXML kommt man auch an Konfigurationsdaten ran, aber so einfach und unflexibel willst du es ja nicht haben :-)

      Wenn ich das so abgebe, bekomm ich bestimmt einen "auf den Sack" :-)

      Komplexer und komplizierter geht immer. Zum Beispiel könnte man statt eines (verschachtelten) Arrays in der Config-Klasse weiteren Klassen vorsehen, die im einfachsten Fall einen Wert aber auch andere individuelle Strukturen enthalten können.

      Wenn ich Dich richtig verstehe, versuchen wir das bereits. Ich hab mal eine Zip-Datei mit einer anfänglichen und unfertigen (was für ein tolles Wort...) Version einer möglichen Config-Implementierung hochgeladen. Wenn Du Lust hast, kannst Du es Dir ja mal ansehen (Vorschläge natürlich sehr erwünscht): http://fsac.de/dat/selfhtml/library.zip

      Was würdet Ihr ganz persönlich bevorzugen, wenn Ihr mit einem Framework arbeitet?

      Zu allgemein gefragt kann ich da nur zu allgemein antworten. Meine aktuellen Bedürfnisse muss es erfüllen können, notfalls durch individuelle Erweiterbarkeit.

      Ok, war ne doofe Frage.

      Wir freuen uns über alle Meinungen, Anmerkungen, Vorschläge oder was-auch-immer, was uns bei unserer Entscheidungsfindung behilflich sein könnte.

      Schamlos bei anderen abschauen, wie die es gelöst haben, ausprobieren, Erfahrungen sammeln, aus deren Fehlern lernen, was bei anderen zu komplex geraten ist, auf einfache(re) Weise nachbauen, dann selbst um so viel benötigte Funktionalität erweitern, biss es mindestens genauso komplex und unüberschaubar geworden ist, ...

      So wird's wahrscheinlich laufen...

      Ps: Sorry, dass das wieder so ein langer Text geworden ist.

      Nö, ich kann auch "lang".

      Dann bin ich beruhigt :-)

      Gruß und nochmal danke,
      Dennis

      1. Hi!

        Scheitert, wenn der Original-Code wegen OpCode-Compilern [...] nicht geändert werden kann.
        Das verstehe ich leider nicht. Wie meinst Du das mit den OpCode-Compilern? In welcher Form spielen die eine Rolle für die Erweiterung des Original-Codes?

        War vielleicht etwas ungünstig formuliert. Der Original-Code ist der, den du schreibst. Wenn man den nicht offenlegen will, liefert man an Kunden vorkompilierten "Byte-Müll". Den kann der Kunde dann zwar verwenden, aber ihn nicht mehr ändern. Dan kann man natürlich als Kunde auch keine Erweiterungen mehr einpflegen.

        Warum erschwert eine Factory das Testen?

        Über eine Factory kann man im Allgemeinen nur aus einer feststehende Anzahl an "Produkten" wählen. Man kann ihr keine Mock-Objekte unterschieben. Vielmehr müsste man dann eine Test-Klasse schreiben, die sich in die Reihe der Produkte eingliedert. Damit ist man deutlich unflexibler als mit Mocks. So ein Mock definiert man ja on-the-fly innerhalb der Test-Methode - und in jeder Test-Methode mit unterschiedlichen Parametern und Reaktionen. Das kannst du mit einer Test-Produkt-Klasse kaum schaffen.

        Muss das ganze TDD-fähig sein? [...]
        Ich wusste bis gerade nicht, was TDD bedeutet (für alle Unwissenden wie mich: Testgetriebene Entwicklung).

        Ausgeschrieben: Test Driven Development. Man schreibt sich zunächst für alle denkbaren und alle auszuschließenden Anwendungsfälle jeweils eine Methode, die diesen Anwendungsfall testet. Vom Testobjekt hat man zunächst nicht mehr als ein Gerippe - also Eigenschaften sind da, Methoden sind aber alle leer. Dann lässt man den Test zum ersten Mal laufen und stellt fest, dass alle Tests fehlschlagen. Sehr gut - nicht dass der Test an sich falsch implementiert ist und einfach so ein positives Ergebnis erzeugt. Nun füllt man das Gerippe mit Leben und schaut, wie der Test immer grüner wird. Für TDD gibt es Frameworks, die einen beim Schreiben solcher Tests unterstützen. Und die schon erwähnten Mocks sind dabei Helfer, die so tun, als seien sie Instanzen eines bestimmten Interfaces, das vom zu testenden Objekt verwendet wird.

        Also, die Config-Klasse soll getestet werden. Die will per DI ein Objekt einer Klasse mit implementiertem Quellen-Interface haben, aus dem sie sich die Konfigurationswerte holen kann. Man nimmt für den Test nun keine Test-Klasse sondern ein Mock-Objekt. Das tut so, als hätte es das Quellen-Interface implementiert und wird so initialisiert, dass beim Aufruf einer der im Interface vereinbarten Methoden ein bestimmter Wert zurückgegeben wird. Nun veranlasst man die Config-Klasse, dass sie etwas macht, das genau diese Methode im angeblichen Quellen-Objekt aufruft und kann dann schauen, wie die Konfig-Klasse auf unterschiedliche vom Mock-Objekt bereitgestellte Rückgabewerte reagiert. Hört sich komplex an? Isses auch. Aber es gibt nicht nur Test-Frameworks sondern auch fertige Mock-Implementationen. (Wobei ich aber für PHP keine aktuelle Marktübersicht habe.)

        Komplexer und komplizierter geht immer. Zum Beispiel könnte man statt eines (verschachtelten) Arrays in der Config-Klasse weiteren Klassen vorsehen, die im einfachsten Fall einen Wert aber auch andere individuelle Strukturen enthalten können.
        Wenn ich Dich richtig verstehe, versuchen wir das bereits. Ich hab mal eine Zip-Datei mit einer anfänglichen und unfertigen (was für ein tolles Wort...) Version einer möglichen Config-Implementierung hochgeladen.

        Darin sehe ich von meinem Beispiel nichts. Im Moment legst du die Werte direkt als neue Eigenschaften im Config-Objekt an. Soweit so einfach. Ich meinte das komplizierter. Es gibt eine Klasse, die im einfachsten Fall einen Wert speichert. Aber es kann auch Klassen geben, die komplexere Strukturen aufnehmen kann. Beide implementieren aber das selbe Interface und dein Config-Objekt speichert nur Objekte dieses Interfaces. - So zumindest könnte man das in einer typsicheren Umgebung machen. Für PHP ist das ziemlicher Overkill. Hier kann ein Array-Element ganz einfach einen skalaren Wert und für Strukturen ein Array oder Objekt aufnehmen. Da ist man ja schon durch die flexible Typisierung flexibel genug.

        (Vorschläge natürlich sehr erwünscht): http://fsac.de/dat/selfhtml/library.zip

        Fsac\Object\ExtendedArrayObject.php

        Kein toller Name. Kannst du den Namen so sprechend machen, dass man die hinzugefügte Funktionalität daraus entnehmen kann?

        public function __construct($allowOverwrite = false, $throwExceptions = false) {
            if (true === $allowOverwrite) {
              $this->allowOverwrite();

        Da spielt es doch überhaupt keine Rolle, ob man true oder 1 übergibt. Also muss da auch kein typsicherer Vergleich hin. Typsicher muss man es nur dann machen, wenn man zum Beispiel zwischen false und 0 unterscheiden muss.

        protected final function ...

        Was'n das? Warum nicht gleich private?

        Fsac\Config\Config - addArray()

        @todo What implementation is better?

        +1 für den Einzeiler.

        Dein ArrayObject implementiert Iterator und ist damit in der Verwendung sehr eingeschränkt, weil man immer nur einen zur gleichen Zeit laufen lassen kann. Mit IteratorInterface wird man da flexibler, weil das so gedacht ist, dass es einen eigenständigen Iterator liefert.

        Und dann ist das ganze Gebilde ja Variante 1 und keine DI.

        Lo!

        1. Hey dedlfix,

          sorry, hat etwas länger gedauert, bis ich nun antworte. Aber ich kann's nicht oft genug sagen: Danke für Deine Hilfe!

          Scheitert, wenn der Original-Code wegen OpCode-Compilern [...] nicht geändert werden kann.
          Das verstehe ich leider nicht. Wie meinst Du das mit den OpCode-Compilern? In welcher Form spielen die eine Rolle für die Erweiterung des Original-Codes?

          War vielleicht etwas ungünstig formuliert. Der Original-Code ist der, den du schreibst. Wenn man den nicht offenlegen will, liefert man an Kunden vorkompilierten "Byte-Müll". Den kann der Kunde dann zwar verwenden, aber ihn nicht mehr ändern. Dan kann man natürlich als Kunde auch keine Erweiterungen mehr einpflegen.

          Ah, verstanden!

          Warum erschwert eine Factory das Testen?

          Über eine Factory kann man im Allgemeinen nur aus einer feststehende Anzahl an "Produkten" wählen. Man kann ihr keine Mock-Objekte unterschieben. Vielmehr müsste man dann eine Test-Klasse schreiben, die sich in die Reihe der Produkte eingliedert. Damit ist man deutlich unflexibler als mit Mocks. So ein Mock definiert man ja on-the-fly innerhalb der Test-Methode - und in jeder Test-Methode mit unterschiedlichen Parametern und Reaktionen. Das kannst du mit einer Test-Produkt-Klasse kaum schaffen.

          Danke für die Erklärung! Verstanden! :-)

          Muss das ganze TDD-fähig sein? [...]
          Ich wusste bis gerade nicht, was TDD bedeutet (für alle Unwissenden wie mich: Testgetriebene Entwicklung).

          Ausgeschrieben: Test Driven Development. Man schreibt sich zunächst für alle denkbaren und alle auszuschließenden Anwendungsfälle jeweils eine Methode, die diesen Anwendungsfall testet. Vom Testobjekt hat man zunächst nicht mehr als ein Gerippe - also Eigenschaften sind da, Methoden sind aber alle leer. Dann lässt man den Test zum ersten Mal laufen und stellt fest, dass alle Tests fehlschlagen. Sehr gut - nicht dass der Test an sich falsch implementiert ist und einfach so ein positives Ergebnis erzeugt. Nun füllt man das Gerippe mit Leben und schaut, wie der Test immer grüner wird. Für TDD gibt es Frameworks, die einen beim Schreiben solcher Tests unterstützen. Und die schon erwähnten Mocks sind dabei Helfer, die so tun, als seien sie Instanzen eines bestimmten Interfaces, das vom zu testenden Objekt verwendet wird.

          Das hört sich echt interessant an. Da muss ich mich glaub ich mal was länger mit auseinandersetzen. Scheint ja relativ komplex (und kompliziert) zu sein.

          Also, die Config-Klasse soll getestet werden. Die will per DI ein Objekt einer Klasse mit implementiertem Quellen-Interface haben, aus dem sie sich die Konfigurationswerte holen kann. Man nimmt für den Test nun keine Test-Klasse sondern ein Mock-Objekt. Das tut so, als hätte es das Quellen-Interface implementiert und wird so initialisiert, dass beim Aufruf einer der im Interface vereinbarten Methoden ein bestimmter Wert zurückgegeben wird. Nun veranlasst man die Config-Klasse, dass sie etwas macht, das genau diese Methode im angeblichen Quellen-Objekt aufruft und kann dann schauen, wie die Konfig-Klasse auf unterschiedliche vom Mock-Objekt bereitgestellte Rückgabewerte reagiert. Hört sich komplex an? Isses auch. Aber es gibt nicht nur Test-Frameworks sondern auch fertige Mock-Implementationen. (Wobei ich aber für PHP keine aktuelle Marktübersicht habe.)

          Auch für diese Erklärung vielen Dank. Ich verstehe zwar, worum es prinzipiell geht, aber da muss ich mich erstmal näher mit beschäftigen.
          Ist PhpUnit so ein Test-Framework?

          Komplexer und komplizierter geht immer. Zum Beispiel könnte man statt eines (verschachtelten) Arrays in der Config-Klasse weiteren Klassen vorsehen, die im einfachsten Fall einen Wert aber auch andere individuelle Strukturen enthalten können.
          Wenn ich Dich richtig verstehe, versuchen wir das bereits. Ich hab mal eine Zip-Datei mit einer anfänglichen und unfertigen (was für ein tolles Wort...) Version einer möglichen Config-Implementierung hochgeladen.

          Darin sehe ich von meinem Beispiel nichts. [...]

          Kannst Du auch nicht. Hab an was ganz anderes gedacht...

          (Vorschläge natürlich sehr erwünscht): http://fsac.de/dat/selfhtml/library.zip

          Dedlfix, ich hab Dir leider eine falsche Version hochgeladen. Die hatte ich vor ein paar Wochen mal um ein paar Dinge zu testen erstellt. Sorry!
          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 hab jetzt unter oben genanntem Link mal eine neue Version hochgeladen, die ich eben mal gemacht habe. Wenn Du Zeit und Lust hast, würde ich mich freuen, wenn Du nochmal kurz drüberschauen könntest. Da ist zwar noch nichts kommentiert und das ist bei weitem noch nicht fertig; aber vielleicht kannst Du mir kurz sagen, ob das jetzt Dependency Injection ist, was ich verwendet habe!?

          Danke, dass Du Dir die Zeit nimmst, mir beim Lernen zu helfen!
          Dennis

          1. 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!

            1. Hey dedlfix,

              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. [...]

              ich finde trotzdem, dass ich das immer wieder sagen kann und sollte. Dir im speziellen, aber auch vielen anderen hier im Forum (ich hoffe, die entsprechenden Stamm-Poster fühlen sich hier auch angesprochen, ohne dass ich sie jetzt im Einzelnen nenne).
              Ich finde es echt super, dass Ihr Eure Freizeit opfert um Leuten wie mir zu helfen und an Eurem Wissen teilhaben lasst. Und das muss auch einfach irgendwie mal gewürdigt werden und sei es nur, dass ich mich bei Euch bedanke!

              (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.

              Dann bin ich zufrieden :-)

              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.

              Deine Beschreibung ist zwar sehr schön und ich meine verstanden zu haben, worum es geht: Ich werde mich dazu aber erstmal noch was einlesen müssen. Das ist mir gerade noch "zu hoch". Wenn ich das was besser verstanden hab, komme ich aber gern auf Deine Hilfe zurück ;-)
              Zum Institut: Es wurde nie "Dependency Injection" oder ähnliches in den Raum geworfen. Vielmehr haben wir uns selbst ein bisschen schlau gemacht, was es überhaupt als "Arbeitsgrundlage" so gibt. Ich weiß auch nicht, ob wir das jetzt tatsächlich mit DI oder was-weiß-ich umsetzen. Aber unabhängig davon interessiert mich das nach Euren Antworten jetzt. Vielleicht können wir das im aktuellen Projekt verwenden, vielleicht kann ich's später mal gebrauchen oder aber ich hab einfach für mich was dazugelernt.

              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.  
                
              Genau dieser Unterschied war bisher wohl das größte Problem in meinem Verständnis von DI.  
                
              
              > 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.  
                
              Ich bastel da noch ein bisschen dran rum und hoffe, ich kann Dir das nächste Mal dann wirklich DI präsentieren. :-)  
                
              
              > Jetzt noch zweimal Kleinkram bezüglich der Klasse Config:  
              >   
              > ~~~php
              
              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.  
                
              Wird erledigt!  
                
              
              > [...]  
              > ~~~php
              
              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;

              Das halte ich persönlich auch für die bessere Schreibweise. Wir hatten uns aber darauf geeinigt, nur eine der beiden Schreibweisen konsequent zu verwenden. Aber wahrscheinlich ist das auch keine gute Wahl, nur (gezwungen) _eine_ Schreibweise zu verwenden. Ein (mit) ausschlaggebender Punkt war ein Artikel von Fabien Potencier zu dem Thema. Was meinst Du dazu?

              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;

                
              Die Schreibweise finde ich persönlich die schlechteste aller Varianten und werd mich damit wohl nie anfreunden können.  
                
              Gruß, Dennis
              
              1. Hi!

                [Trinitätsoperator vs. if-else]
                Wir hatten uns aber darauf geeinigt, nur eine der beiden Schreibweisen konsequent zu verwenden. Aber wahrscheinlich ist das auch keine gute Wahl, nur (gezwungen) _eine_ Schreibweise zu verwenden. Ein (mit) ausschlaggebender Punkt war ein Artikel von Fabien Potencier zu dem Thema. Was meinst Du dazu?

                Er fängt ja schon schön an: "Mikrooptimierung, gern verwendet ... aber nutzlos". Ich denke, man sollte sich darüber keine unnötigen Sorgen machen. Die Unterschiede sind üblicherweise dermaßen minimal, dass es sich nicht lohnt, Nachdenk- und Implementationsaufwand oder Flexibilität durch Prinzipien zu opfern. - Also, Nachdenken ist nicht verkehrt - im Gegenteil - und man kann sich ruhig auch mal Vergleiche ansehen und selbst welche anstellen, aber was soll's? Um überhaupt etwas messen und spüren zu können, nimmt man üblicherweise "im Labor" eine sehr hohe Zahl an Wiederholungen und misst die Laufzeit. Hat man etwas vergleichbares in der Praxis? Nein. Denn in der Praxis nimmt man Wiederholungen, um mehrfach Daten zu erzeugen oder durchzuarbeiten. Man hat also entweder eine große Menge Daten vorliegen oder erzeugt sich eine. Und dann hat man den Transport dieser Datenmenge, der einen wesentlich größeren Zeitanteil verschlingt als die Mikrooptimierung allein rausarbeiten kann.

                Wenn die Anwendung lahm ist, dann muss man sowieso erstmal analysieren, woran es den konkret hapert und wo am meisten Performancesteigerung zu erwarten ist. Wenn die Datenbank trödelt (z.B. weil sie keinen Index verwenden kann), muss man nicht die Handvoll String-Operation zum SQL-Statement-Zusammenbau optimieren, sondern das Statement an sich und/oder die Tabellenstruktur überarbeiten.

                Lo!

                1. Hey dedlfix,

                  [Trinitätsoperator vs. if-else]
                  Wir hatten uns aber darauf geeinigt, nur eine der beiden Schreibweisen konsequent zu verwenden. Aber wahrscheinlich ist das auch keine gute Wahl, nur (gezwungen) _eine_ Schreibweise zu verwenden. Ein (mit) ausschlaggebender Punkt war ein Artikel von Fabien Potencier zu dem Thema. Was meinst Du dazu?

                  Er fängt ja schon schön an: "Mikrooptimierung, gern verwendet ... aber nutzlos". Ich denke, man sollte sich darüber keine unnötigen Sorgen machen.

                  über Mikro-Optimierung wollten wir uns eigentlich keine Gedanken machen. Es stand nur im Raum, dass nur eine einzige Schreibweise konsequent im gesamten Framework verwendet werden sollte. Aber wie kann man einigermaßen objektiv beurteilen, welche der Varianten verwendet wird? Deshalb war das unser einziger Ansatz.
                  Wie in meiner vorherigen Antwort an Dich beschrieben müssen wir uns damit aber zum Glück erstmal nicht rumschlagen.
                  Falls es Dich interessiert: Bisher habe ich "objektiv" entschieden, was _ich_ für schöner bzw. lesbarer halte ;-)

                  [...] Wenn die Anwendung lahm ist, dann muss man sowieso erstmal analysieren, woran es den konkret hapert und wo am meisten Performancesteigerung zu erwarten ist. Wenn die Datenbank trödelt (z.B. weil sie keinen Index verwenden kann), muss man nicht die Handvoll String-Operation zum SQL-Statement-Zusammenbau optimieren, sondern das Statement an sich und/oder die Tabellenstruktur überarbeiten.

                  Das halte ich auch für wichtiger. Und auch Deiner vorherigen Ausführung zu dem (Un-)Sinn von Mikro-Optimierung (im Allgemeinen) kann ich nichts hinzufügen (nur nicht, dass Du denkst, ich lese mir Deine Antworten nicht gründlich durch; aber ich weiß nicht, was ich darauf antworten sollte).

                  Gruß, Dennis

  4. Hallo,

    Frage:
    Also nun meine Frage an Euch: Welche Möglichkeiten haltet Ihr noch für denkbar? Was haltet Ihr von den oben genannten Möglichkeiten? Welche Vor- oder Nachteile fallen Euch ein? Was würdet Ihr ganz persönlich bevorzugen, wenn Ihr mit einem Framework arbeitet?

    Wir freuen uns über alle Meinungen, Anmerkungen, Vorschläge oder was-auch-immer, was uns bei unserer Entscheidungsfindung behilflich sein könnte.
    Solltet Ihr Fragen zu oben beschriebenem haben, habe ich mich unklar ausgedrückt oder etwas vergessen, so schreibt bitte einfach kurz!

    Das Zend Framework fasst viele dieser Überlegungen zusammen und hat sich in seiner Entstehung auch an anderen Frameworks orientiert. Sicherlich interessant in dem Zusammenhang, welche Lehren sie in der Version 2.0 aus den bisherigen Erfahrungen gezogen haben. Ich würde mich an diesem Aufbau orientieren...;

    http://framework.zend.com/wiki/display/ZFDEV2/Zend+Framework+2.0+Roadmap

    Gruß

    jobo

    1. Hey jobo,

      Das Zend Framework fasst viele dieser Überlegungen zusammen und hat sich in seiner Entstehung auch an anderen Frameworks orientiert. Sicherlich interessant in dem Zusammenhang, welche Lehren sie in der Version 2.0 aus den bisherigen Erfahrungen gezogen haben. Ich würde mich an diesem Aufbau orientieren...;

      http://framework.zend.com/wiki/display/ZFDEV2/Zend+Framework+2.0+Roadmap

      mit dem Zend Framework (Version 1) arbeite ich privat auch. Der Tipp mit Version 2 ist super! Da werde ich mich mal etwas einlesen und das mal mit der vorherigen Version vergleichen.

      Danke und Gruß,
      Dennis

      1. Hallo,

        Hey jobo,

        Das Zend Framework fasst viele dieser Überlegungen zusammen und hat sich in seiner Entstehung auch an anderen Frameworks orientiert. Sicherlich interessant in dem Zusammenhang, welche Lehren sie in der Version 2.0 aus den bisherigen Erfahrungen gezogen haben. Ich würde mich an diesem Aufbau orientieren...;

        http://framework.zend.com/wiki/display/ZFDEV2/Zend+Framework+2.0+Roadmap

        mit dem Zend Framework (Version 1) arbeite ich privat auch. Der Tipp mit Version 2 ist super! Da werde ich mich mal etwas einlesen und das mal mit der vorherigen Version vergleichen.

        Ich hatte mich schon immer gefragt, ob man nicht eine Art ZF-light basteln könnte (;-). Die Lizenz würde es ja vermutlich hergeben. Von der Struktur und der in vielen Fällen konsequenten Art der Vorgehens fand ich es halt bisher recht beispielhaft. Auch die Jungs im Hintergrund um Herrn Weyer O Phinney scheinen mir ganz fit (s. diverse Webinars u.a. die komplette Dokumentation).

        Gruß

        jobo

        1. Hey jobo,

          Ich hatte mich schon immer gefragt, ob man nicht eine Art ZF-light basteln könnte (;-). Die Lizenz würde es ja vermutlich hergeben.

          So was wäre auf jeden Fall was Feines! Hab auch schon mehrfach daran gedacht, dass ein ZF-light für viele Fälle reichen würde.
          Schön wäre natürlich, wenn mit ZF 2.0 so eine Art "Plugin-System" käme. Also so, dass die eigentliche Installation nur ganz minimal ist und man alles andere erst später, wenn man es braucht, hinzufügen kann.

          Von der Struktur und der in vielen Fällen konsequenten Art der Vorgehens fand ich es halt bisher recht beispielhaft. Auch die Jungs im Hintergrund um Herrn Weyer O Phinney scheinen mir ganz fit (s. diverse Webinars u.a. die komplette Dokumentation).

          Auf jeden Fall. Als ich mich jetzt mit Dependency Injection auseinandergesetzt habe, bin ich auch auf den Blog von Fabien Potencier aufmerksam geworden. Da findet man auch einige interessante Sachen, aber vor allem bezüglich Symfony und nicht ZF. Vielleicht findest Du da ja auch was interessantes.

          Gruß, Dennis

          1. Hi!

            Ich hatte mich schon immer gefragt, ob man nicht eine Art ZF-light basteln könnte (;-). Die Lizenz würde es ja vermutlich hergeben.
            So was wäre auf jeden Fall was Feines! Hab auch schon mehrfach daran gedacht, dass ein ZF-light für viele Fälle reichen würde.
            Schön wäre natürlich, wenn mit ZF 2.0 so eine Art "Plugin-System" käme. Also so, dass die eigentliche Installation nur ganz minimal ist und man alles andere erst später, wenn man es braucht, hinzufügen kann.

            Mit anderen Worten: ZF à la PEAR.

            ZF ist als ein grundlegendes Framwork konzipiert, also dass man zumindest den MVC-Teil als grundlegende Struktur seines eigenen Projekts nimmt und vom Rest je nach Bedarf. PEAR ist als lose Sammlung ausgelegt, von dem man nach Bedarf Teile in sein wie auch immer strukturiertes Projekt nehmen kann. Deswegen kann man von PEAR jedes Paket einzeln (plus Abhängigkeiten) installieren. Es braucht nun eigentlich kein ZF-light, wenn die ZF-Teile genauso flexibel "dazubuchbar" wären. Was aber vorraussetzt, dass die einzelnen Teile nicht so überladen sind dass ein Zweck von ZF-light wäre, auch noch aus Klassen einige Teile wegzulassen. (Allerdings muss ich dazusagen, dass ich mich mit dem ZF schon seit Vor-1.0-Zeiten nicht mehr auseinandergesetzt habe (und auch andere PHP-Frameworks nicht angeschaut habe). Nach einer kurzen Python-Phase bin ich nun lieber bei C# und .NET. Aber Programmierphilosophien und Entwurfsmuster findet man ja überall gleichermaßen vor.)

            Lo!

            1. Hallo,

              Mit anderen Worten: ZF à la PEAR.

              Nein. ZF ohne Konfiguration. Config ist dann zB. INI (und man kann nicht wählen), DB ist dann eben MySQL, layout ist MVC ...;

              ZF ist als ein grundlegendes Framwork konzipiert, also dass man zumindest den MVC-Teil als grundlegende Struktur seines eigenen Projekts nimmt und vom Rest je nach Bedarf. PEAR ist als lose Sammlung ausgelegt, von dem man nach Bedarf Teile in sein wie auch immer strukturiertes Projekt nehmen kann.

              Das geht bei ZF ja auch. Jede Klasse hat die Abhängigkeiten im Grunde in einem Ordner. PEAR braucht ja so wie ich das beim Mailen mal sah auch die PEAR.php in jedem Fall. Du kannst doch Zend_Mail genau so ohne die anderen Klassen nutzen bzw. das komplette Framework.

              Ich glaube, mit den Anfängen kann man das mittlerweile nicht mehr wirklich vergleichen. Schon garnicht, wenns in Richtung 2.0 geht. Das Interessante daran ist ja dann, dass sie quasi nochmal von vorne anfangen, ohne Rücksicht auf Rückwärtskompatibilität. Und somit auch resummieren, wo die bisherigen Schwachstellen waren.

              Gruß

              jobo

  5. Moin!

    Komponenten von bereits existierenden Frameworks oder anderen Drittanbietern sollen laut Aufgabenstellung nicht verwendet werden.

    Wäre ja auch noch schöner, wenn man sich viel Arbeit spart und einfach fremden Code importiert... ;->

    Beispiele:
    Um das "Problem" zu verdeutlichen, möchte ich von einer Klasse ausgehen, die Konfigurationsdaten aus verschiedenen Quellen (z.B. INI, XML, ...) lädt und anschließend für späteren Zugriff speichert. Folgende Möglichkeiten zur Umsetzung haben wir uns bisher überlegt:

    Nur weil "fremde Frameworks" nicht benutzt werden dürfen, muss man sie ja nicht auch als Inspirationsquelle ignorieren.

    Nun hast du mit "Konfiguration" ausgerechnet das Themengebiet ausgesucht, das viele diskussionswürdige Aspekte enthält. "Die Konfiguration der Software" ist nämlich sowohl dynamisch (je nach eingelesener Datenquelle), als auch statisch (es kann nur eine Variante zur Zeit geben), sowohl global (die Konfiguration gilt überall gleich) als auch lokal (nicht jede Konfigurationsvariable ist überall gültig und/oder relevant) - und letztendlich ist immer die Frage: Wie kommt die nutzende Klasse konkret an die gewünschten Werte?

    1. Einzelne Klasse
      Die Klasse enthält lediglich je eine eigene Funktion für die möglichen Quellen.

    WENN ich die Konfiguration in einer einzelnen Klasse ablegen würde, dann darin direkt "eingemauert" als PHP-Code, und nicht von irgendwoher eingelesen. Die Methoden dieser Klasse erlauben dann den Zugriff auf die Werte, und eventuell kann man auch irgendwie umstellen, welche Variante tatsächlich ausgeliefert wird.

    1. Vererbung
      Unterklasse ist beispielsweise "Ini", Oberklasse "Config". "Ini" parsed die Ini-Datei und speichert die Konfigurationen wegen der Vererbung "quasi in sich selbst". "Config" ist als abstrakt definiert, sodass nur "Ini" direkt aufgerufen werden kann. Es werden also die einzelnen Funktionen aus 1) in eine eigene Klasse ausgegliedert.

    Vererbung von Klassen ist dann schön, wenn:

    • es mehr als eine erbende Klasse gibt (wenn das mal irgendwann "sein könnte", gilt: YAGNI)
    • diese zwei oder mehr Klassen eine gemeinsame Codebasis haben, die man durch das Verlagern in eine Elternklasse vereinheitlichen kann
    • sich dadurch in einem Bereich nicht mehr als drei Vererbungsebenen ergeben (zuviel Vererbung macht den Code undurchsichtig und damit schwer wartbar): Foo_Bar_Baz extends Foo_Bar_Abstract, Foo_Bar_Abstract extends Foo_Abstract - mehr nicht. Entscheidend für die "Vererbungsebenen" ist allerdings, welche Trennstellen man definieren kann. Wenn Foo_Bar_Baz eine Klasse eines externen Frameworks ist, die man seinerseits nochmal erweitern will, dann wäre diese Vererbung wohl die zweite Ebene, weil "Bereich" sich nur auf den eigenen Einflussbereich bezieht, auch wenn man dadurch insgesamt vier Vererbungsstufen hat.

    Es ist übrigens sehr empfehlenswert, sich von Anfang an ein vernünftiges Namensschema zur Klassenbenennung zu definieren - insbesondere, weil man heutzutage definitiv Autoloading benutzen will. Für sowas gibts schon Standards, der einzig relevante für PHP dürfte "PSR-0" sein (PSR steht für PHP Standard Recommendation, die 0 ist die laufende Nummer). Das Zend-Framework setzt dieses Namensschema ein, und ich halte es für sehr empfehlenswert.

    Insofern kannst du eigentlich keine Klasse "Ini" haben, wenn die von "Config" erbt, sondern müsstes sie "Config_Ini nennen. Rein "zufällig" hat das Zend-Framework sowas schon vorgemacht: "Zend_Config" ist die Hauptklasse, aus der Konfigurationswerte herauskommen, und Zend_Config_Ini ist die Klasse, die Ini-Dateien einliest und parst. Die Frage wäre, ob Config_Ini von Config erben muss. Im Zend-Framework wird das gemacht, ich würde es aber nicht als zwingend ansehen.

    1. "Helper"-Klasse
      Klasse "Ini" implementiert eine Interface "Sources". Im Konstruktor von Klasse "Config" wird der Quellen-Typ ermittelt und dementsprechend eine der Quellen-Klassen, also z.B. "Ini", aufgerufen, welche anschließend ein Array von Konfigurationsdaten zurückliefert. Dieses Array wird anschließend von "Config" gespeichert. ("Ini" erbt nicht von "Config")

    Klingt wie Zend-Framework. :)

    Interfaces sind ja dafür da, das Vorhandensein von öffentlichen Methoden zu garantieren. Das lohnt sich also nur, wenn das Interface wirklich in mehr als einer Klasse verwendet wird. Ich habe schon Designs gesehen, in denen ein leeres Interface (keine definierten Methoden) einfach nur "weil man es so macht" definiert und von einer einzigen Klasse implementiert wurde.

    1. Factory Method
      Eine Mischung aus 2) und 3). Unterschied: Oberklasse "Config" besitzt eine statische Fabrik-Methode. Statt wie in 2) muss diese bemüht werden, den richtigen "Ansprechpartner" zu finden und nicht der Konstruktor. Der Konstruktor ist in diesem Fall mindestens "protected".

    Klingt nicht wie das Factory-Pattern, sondern wie das Singleton-Pattern. Und DAS sollte man meiden! Es ist nämlich nicht gut testbar.

    1. Dependency Injection (Verwendet der nun folgende Fall überhaupt dieses Pattern?)
      Eine Mischung aus 3) und 4). Unterschied: Hier bestimmt der Konstruktor von "Config", welcher Quellen-Typ vorliegt und instanziiert die entsprechende Helfer-Klasse. Die Helferklasse erhält eine Referenz von "Config", in die sie mittels der Methoden von "Config" Eigenschaften speichern kann.

    Dependency Injection ist, wenn ein Objekt zum Funktionieren ein anderes Objekt benötigt, welches es aber nicht selbst erzeugt, sondern von Außen reingereicht bekommt.

    Wenn der Konstruktor des Objekts also selbst was instanziiert, dann ist das KEINE Dependency Injection.

    Auch hier ist wieder das Stichwort "Testbarkeit" ausschlaggebend. Wenn man ein Objekt testen will, dass von ganz allein andere Objekte instanziiert und benutzt, dann kann man das eigentliche Objekt nicht vollständig testen. Denn man muss auch kontrollieren können, ob und wie das zu testende Objekt sein inneres Objekt anspricht. Sowas geht nur, wenn man anstatt des echten inneren Objekts eine Testklasse hineintut, die die Methodenaufrufe registriert und mit vorgefertigten Resultaten antworten kann.

    Frage:
    Also nun meine Frage an Euch: Welche Möglichkeiten haltet Ihr noch für denkbar? Was haltet Ihr von den oben genannten Möglichkeiten? Welche Vor- oder Nachteile fallen Euch ein? Was würdet Ihr ganz persönlich bevorzugen, wenn Ihr mit einem Framework arbeitet?

    Was ich bevorzuge: Dokumentation, Testabdeckung und Nutzung etablierter Standards, und nicht die hundertdreiundzwanzigste Neuerfindung eines MVC-Frameworks.

    Ich meine: Ich kann's ja verstehen, wenn man ein Framework nicht mag, weil es die eigene Philosophie nicht unterstützt. Deswegen gibt's ja schon mehr als eins. Und gerade das Zend Framework deckt schon extrem viele typische Aufgaben ab, denen man im Web-Kontext immer wieder begegnet.

    Wir freuen uns über alle Meinungen, Anmerkungen, Vorschläge oder was-auch-immer, was uns bei unserer Entscheidungsfindung behilflich sein könnte.
    Solltet Ihr Fragen zu oben beschriebenem haben, habe ich mich unklar ausgedrückt oder etwas vergessen, so schreibt bitte einfach kurz!

    Existierende Frameworks angucken. Benutzen. Ideen erkennen. Und wenn's sein muss, dann nachbauen.

    - Sven Rautenberg

    1. Hallo,

      Insofern kannst du eigentlich keine Klasse "Ini" haben, wenn die von "Config" erbt, sondern müsstes sie "Config_Ini nennen. Rein "zufällig" hat das Zend-Framework sowas schon vorgemacht: "Zend_Config" ist die Hauptklasse, aus der Konfigurationswerte herauskommen, und Zend_Config_Ini ist die Klasse, die Ini-Dateien einliest und parst. Die Frage wäre, ob Config_Ini von Config erben muss. Im Zend-Framework wird das gemacht, ich würde es aber nicht als zwingend ansehen.

      Das ginge dann viell. in Richtung ZF-light (https://forum.selfhtml.org/?t=206131&m=1398677). Aber viell. geht die 2.0er Version ja in die Richtung. Viell. sieht es mit der Nutzung von Namespaces auch anders aus?

      Gruß

      jobo

      1. Moin!

        Insofern kannst du eigentlich keine Klasse "Ini" haben, wenn die von "Config" erbt, sondern müsstes sie "Config_Ini nennen. Rein "zufällig" hat das Zend-Framework sowas schon vorgemacht: "Zend_Config" ist die Hauptklasse, aus der Konfigurationswerte herauskommen, und Zend_Config_Ini ist die Klasse, die Ini-Dateien einliest und parst. Die Frage wäre, ob Config_Ini von Config erben muss. Im Zend-Framework wird das gemacht, ich würde es aber nicht als zwingend ansehen.

        Das ginge dann viell. in Richtung ZF-light (http://forum.de.selfhtml.org/my/?t=206131&m=1398677). Aber viell. geht die 2.0er Version ja in die Richtung. Viell. sieht es mit der Nutzung von Namespaces auch anders aus?

        Dass hier ausgerechnet die Konfiguration als Aufhänger diskutiert wird, halte ich auch eher für unglücklich.

        Es gibt eigentlich nur zwei Situationen:

        1. Wenn man tatsächlich ein "Framework" programmiert, dann muss man die möglichen Anforderungen aller möglichen User abdecken und benötigt dafür ein entsprechend breit gefächertes Angebot an Features. Das Zend Framework erlaubt das Lesen von INI, XML, YAML und JSON-Konfigurationsdateien - das sollte alles mögliche abdecken.

        2. Oder man programmiert für den eigenen, identifizierten Bedarf. Das macht viele Dinge sehr viel einfacher, weil man einfach ein paar Annahmen treffen darf, die sich in der Realität im Produktivbetrieb genau so, wie vorgesehen verhalten. Das Zend-Framework muss beispielsweise aktuell die PHP-Versionen ab 5.2.6 abdecken, also auch mit 5.3 funktionieren, aber ohne dessen Features nutzen zu können, und muss auch zuverlässig detektieren, welche eventuell optional vom Admin angebotenen oder deaktivierten PHP-Erweiterungen verfügbar sind. Wenn man kein Framework schreibt, sondern "nur" seine eigene grundlegende Klassenbibliothek, dann kann man sich diesen ganzen Kompatibilitätskrempel komplett sparen und seinen Code auf die Betriebsumgebung maßschneidern.

        Das Konfigurationsproblem lässt sich also entweder aufwendig, komplex und fehleranfällig mit viel "universellem" Code lösen, oder sehr banal, einfach und performant mit sehr konkretem Code: Man kann einfach eine Liste von Konstantendefinitionen in PHP-Code tun und zu Beginn ausführen. Man kann auch eine "Konfigurationsklasse" mit einem statischen internen Array für die Werte befüllen und mit statischen Methoden auslesen. INI-oder gar XML-Dateien veredeln Konfigurationsparameter nicht.

        Je schneller das Konfigurationsproblem mit einer funktionierenden Lösung versehen ist, desto schneller kann man sich um die wirklich wichtigen Probleme kümmern.

        - Sven Rautenberg

        1. Hallo,

          1. Wenn man tatsächlich ein "Framework" programmiert, dann muss man die möglichen Anforderungen aller möglichen User abdecken und benötigt dafür ein entsprechend breit gefächertes Angebot an Features. Das Zend Framework erlaubt das Lesen von INI, XML, YAML und JSON-Konfigurationsdateien - das sollte alles mögliche abdecken.

          Genau deshalb dachte ich bei den Versuchen, mich da einzuarbeiten immer wieder: wieso gibts kein ZF-light. Das kann dann eben nur INI zB. und das wars. Diese ganzen Konfigurationsmöglichkeiten machen es für einen Anfänger halt recht komplex. Mir ist so, als wenn ich das Argument auch schon mal hie und da viell. sogar aus den eigenen Reihen in Bezug auf ZF 2.0 gelesen hätte. Klar aber auch, dass man bei einem solchen Framework natürlich gerade schaut, möglichst viele Anwendungsfälle bzw. Konfigurationen zu ermöglichen.

          Das Konfigurationsproblem lässt sich also entweder aufwendig, komplex und fehleranfällig mit viel "universellem" Code lösen, oder sehr banal, einfach und performant mit sehr konkretem Code: Man kann einfach eine Liste von Konstantendefinitionen in PHP-Code tun und zu Beginn ausführen. Man kann auch eine "Konfigurationsklasse" mit einem statischen internen Array für die Werte befüllen und mit statischen Methoden auslesen. INI-oder gar XML-Dateien veredeln Konfigurationsparameter nicht.

          Je nachdem, wer auf die Konfigurationen zugreifen können sollte, wäre eine Liste innerhalb einer Klasse vielleicht nicht so sinnig? Was ich mal probiert hatte war ein globales Array als PHP-Code a la:

          config/config.php

            
          $GLOBALS["config"]["allowedCategories"] = array("abc","abd","abf");  
          $GLOBALS["config"]["titles"]["kuerzel"] = "ein richtiger Titel";  
          $GLOBALS["config"]["titles"]["kuerzel2"] = "ein richtiger zweiter Titel";  
          
          

          Gruß

          jobo

          1. Hey jobo,

            bei den vielen Beiträgen ist mir Deine Antwort irgendwie "durch die Lappen gegangen".

            1. Wenn man tatsächlich ein "Framework" programmiert, dann muss man die möglichen Anforderungen aller möglichen User abdecken und benötigt dafür ein entsprechend breit gefächertes Angebot an Features. Das Zend Framework erlaubt das Lesen von INI, XML, YAML und JSON-Konfigurationsdateien - das sollte alles mögliche abdecken.

            Genau deshalb dachte ich bei den Versuchen, mich da einzuarbeiten immer wieder: wieso gibts kein ZF-light. Das kann dann eben nur INI zB. und das wars. Diese ganzen Konfigurationsmöglichkeiten machen es für einen Anfänger halt recht komplex. Mir ist so, als wenn ich das Argument auch schon mal hie und da viell. sogar aus den eigenen Reihen in Bezug auf ZF 2.0 gelesen hätte. Klar aber auch, dass man bei einem solchen Framework natürlich gerade schaut, möglichst viele Anwendungsfälle bzw. Konfigurationen zu ermöglichen.

            Ich finde das Anbieten mehrerer Formate schon sinnig und gar nicht so komplex. Vor allem (wie Du ja schon erwähnt hast), weil man ja auch (in vielen Fällen) nur einzelne Komponenten verwenden kann.
            Was mich vielmehr stört ist, dass so viele "Komfort-Methoden" verwendet werden. Damit meine ich, dass eine Methode als Parameter beispielsweise einen String, ein Array oder ein Objekt akzeptiert. Das finde ich unübersichtlich. Besser wäre meiner Meinung nach hier nur eine Möglichkeit anzubieten und das (nach Möglichkeit) konsequent.
            Und einige der Wrapper-Methoden für andere Klassen-Methoden gehören für mich auch weg.

            Das Konfigurationsproblem lässt sich also entweder aufwendig, komplex und fehleranfällig mit viel "universellem" Code lösen, oder sehr banal, einfach und performant mit sehr konkretem Code: Man kann einfach eine Liste von Konstantendefinitionen in PHP-Code tun und zu Beginn ausführen. Man kann auch eine "Konfigurationsklasse" mit einem statischen internen Array für die Werte befüllen und mit statischen Methoden auslesen. INI-oder gar XML-Dateien veredeln Konfigurationsparameter nicht.

            Je nachdem, wer auf die Konfigurationen zugreifen können sollte, wäre eine Liste innerhalb einer Klasse vielleicht nicht so sinnig? Was ich mal probiert hatte war ein globales Array als PHP-Code a la:

            config/config.php

            $GLOBALS["config"]["allowedCategories"] = array("abc","abd","abf");
            $GLOBALS["config"]["titles"]["kuerzel"] = "ein richtiger Titel";
            $GLOBALS["config"]["titles"]["kuerzel2"] = "ein richtiger zweiter Titel";

              
            Die Globals finde ich persönlich unübersichtlich. Da finde ich es schon besser, das in eine Klasse auszulagern. Die kann ja auch von überall aus erreichbar (also "quasi-Globals") sein. Aber ich habe zumindest eine Trennung von Anwendungs- und Allgemein-Konfigurationen.  
              
            Gruß, Dennis
            
    2. Hey Sven,

      auch Dir herzlichen Dank für Deine Antwort!

      Komponenten von bereits existierenden Frameworks oder anderen Drittanbietern sollen laut Aufgabenstellung nicht verwendet werden.

      Wäre ja auch noch schöner, wenn man sich viel Arbeit spart und einfach fremden Code importiert... ;->

      Allerdings :-)

      Nur weil "fremde Frameworks" nicht benutzt werden dürfen, muss man sie ja nicht auch als Inspirationsquelle ignorieren.

      Ich glaube das ist das, was dedlfix und jobo auch schon versucht haben mir klarzumachen. Aber irgendwie hab ich das immer "überlesen" :-) Aber Ihr habt ja alle recht: Als erstes werde ich mich jetzt mal mit verschiedenen Frameworks auseinandersetzen.
      Wisst Ihr eigentlich, ob es laut den verwendeten Lizenzen (bspw. vom ZF) erlaubt ist, Methoden 1:1 zu übernehmen und "in ein neues Gewand" zu packen? Dann wären schon viele Probleme gelöst :-)

      Nun hast du mit "Konfiguration" ausgerechnet das Themengebiet ausgesucht, das viele diskussionswürdige Aspekte enthält. "Die Konfiguration der Software" ist nämlich sowohl dynamisch (je nach eingelesener Datenquelle), als auch statisch (es kann nur eine Variante zur Zeit geben), sowohl global (die Konfiguration gilt überall gleich) als auch lokal (nicht jede Konfigurationsvariable ist überall gültig und/oder relevant) - und letztendlich ist immer die Frage: Wie kommt die nutzende Klasse konkret an die gewünschten Werte?

      Ich muss gestehen, so genau habe ich darüber noch gar nicht nachgedacht. Wo ich das so lese, ist das Beispiel wohl tatsächlich unglücklich.
      Wir sind da etwas naiv drangegangen und haben einfach gedacht, jede Anwendung braucht eine Konfiguration. Und eine Konfiguration ist für jeden recht einfach zu verstehen und man kann daran die generelle Vorgehensweise testen. So einfach, so blöd...

      1. Einzelne Klasse [...]

      WENN ich die Konfiguration in einer einzelnen Klasse ablegen würde, dann darin direkt "eingemauert" als PHP-Code, und nicht von irgendwoher eingelesen. Die Methoden dieser Klasse erlauben dann den Zugriff auf die Werte, und eventuell kann man auch irgendwie umstellen, welche Variante tatsächlich ausgeliefert wird.

      Wäre das nicht vielleicht eine gute Möglichkeit für einen Cache? Also wenn man zum Beispiel eine XML-Konfiguration einliest und die Klasse die Konfiguration anschließend als "reine PHP-Klasse" speichert. So würde man sich ja das parsen sparen - obwohl ich nicht weiß, ob das von der Optimierung her viel ausmacht.

      1. Vererbung [...]

      Vererbung von Klassen ist dann schön, wenn:

      • es mehr als eine erbende Klasse gibt (wenn das mal irgendwann "sein könnte", gilt: YAGNI)

      YAGNI war mir bis gerade auch noch kein Begriff. Wieder mal für alle (laut Wikipedia): "YAGNI steht für “You Ain’t Gonna Need It”, zu deutsch: „Du wirst es nicht brauchen”". Verstanden!

      [...]

      • sich dadurch in einem Bereich nicht mehr als drei Vererbungsebenen ergeben (zuviel Vererbung macht den Code undurchsichtig und damit schwer wartbar): Foo_Bar_Baz extends Foo_Bar_Abstract, Foo_Bar_Abstract extends Foo_Abstract - mehr nicht. Entscheidend für die "Vererbungsebenen" ist allerdings, welche Trennstellen man definieren kann. Wenn Foo_Bar_Baz eine Klasse eines externen Frameworks ist, die man seinerseits nochmal erweitern will, dann wäre diese Vererbung wohl die zweite Ebene, weil "Bereich" sich nur auf den eigenen Einflussbereich bezieht, auch wenn man dadurch insgesamt vier Vererbungsstufen hat.

      Auch gut zu wissen, an welchem Wert wir uns grob orientieren sollten.

      Es ist übrigens sehr empfehlenswert, sich von Anfang an ein vernünftiges Namensschema zur Klassenbenennung zu definieren - insbesondere, weil man heutzutage definitiv Autoloading benutzen will. Für sowas gibts schon Standards, der einzig relevante für PHP dürfte "PSR-0" sein (PSR steht für PHP Standard Recommendation, die 0 ist die laufende Nummer). Das Zend-Framework setzt dieses Namensschema ein, und ich halte es für sehr empfehlenswert.

      Du hast uns schon wieder ne Menge Arbeit abgenommen. Haben heute morgen noch darüber diskutiert, wie die Benennung bei der Verwendung von Namespaces aussieht. Hier übrigens der Link zu PSR-0.

      [...] Die Frage wäre, ob Config_Ini von Config erben muss. Im Zend-Framework wird das gemacht, ich würde es aber nicht als zwingend ansehen.

      Fällt Dir - außer bei DI - ein Fall ein, wo die Vererbung in diesem Fall keinen Sinn machen würde?

      1. "Helper"-Klasse [...]

      Klingt wie Zend-Framework. :)

      Also wieder mal ein Fall von "versucht, das Rad neu zu erfinden".

      [...] Ich habe schon Designs gesehen, in denen ein leeres Interface (keine definierten Methoden) einfach nur "weil man es so macht" definiert und von einer einzigen Klasse implementiert wurde.

      In so nem Fall würde sogar ich mich wundern, was das soll :-)

      1. Factory Method [...]
        Klingt nicht wie das Factory-Pattern, sondern wie das Singleton-Pattern. Und DAS sollte man meiden! Es ist nämlich nicht gut testbar.

      Singleton sollte das nicht sein. Hab mich wohl ein bisschen schwierig ausgedrückt.

      1. Dependency Injection (Verwendet der nun folgende Fall überhaupt dieses Pattern?) [...]

      Dependency Injection ist, wenn ein Objekt zum Funktionieren ein anderes Objekt benötigt, welches es aber nicht selbst erzeugt, sondern von Außen reingereicht bekommt.

      Wenn der Konstruktor des Objekts also selbst was instanziiert, dann ist das KEINE Dependency Injection.

      So hat dedlfix das auch erklärt. Ich bin dabei, das umzusetzen. Danke für die Erklärung!

      Auch hier ist wieder das Stichwort "Testbarkeit" ausschlaggebend. Wenn man ein Objekt testen will, dass von ganz allein andere Objekte instanziiert und benutzt, dann kann man das eigentliche Objekt nicht vollständig testen. Denn man muss auch kontrollieren können, ob und wie das zu testende Objekt sein inneres Objekt anspricht. Sowas geht nur, wenn man anstatt des echten inneren Objekts eine Testklasse hineintut, die die Methodenaufrufe registriert und mit vorgefertigten Resultaten antworten kann.

      Sind das die "ominösen Mock-Objekte"?

      Frage:
      Also nun meine Frage an Euch: Welche Möglichkeiten haltet Ihr noch für denkbar? Was haltet Ihr von den oben genannten Möglichkeiten? Welche Vor- oder Nachteile fallen Euch ein? Was würdet Ihr ganz persönlich bevorzugen, wenn Ihr mit einem Framework arbeitet?

      Was ich bevorzuge: Dokumentation, Testabdeckung und Nutzung etablierter Standards, und nicht die hundertdreiundzwanzigste Neuerfindung eines MVC-Frameworks.

      Ja, macht Sinn :-)

      [...]
      Existierende Frameworks angucken. Benutzen. Ideen erkennen. Und wenn's sein muss, dann nachbauen.

      Damit werden wir uns jetzt erstmal beschäftigen!

      Danke und Gruß,
      Dennis

      1. Moin!

        1. Einzelne Klasse [...]

        WENN ich die Konfiguration in einer einzelnen Klasse ablegen würde, dann darin direkt "eingemauert" als PHP-Code, und nicht von irgendwoher eingelesen. Die Methoden dieser Klasse erlauben dann den Zugriff auf die Werte, und eventuell kann man auch irgendwie umstellen, welche Variante tatsächlich ausgeliefert wird.

        Wäre das nicht vielleicht eine gute Möglichkeit für einen Cache? Also wenn man zum Beispiel eine XML-Konfiguration einliest und die Klasse die Konfiguration anschließend als "reine PHP-Klasse" speichert. So würde man sich ja das parsen sparen - obwohl ich nicht weiß, ob das von der Optimierung her viel ausmacht.

        Die Gegenfrage wäre an dieser Stelle dann: Warum überhaupt erst XML? Das ist vom Format her ja auch nicht wirklich pflegeleicht, man muss mit Sachkenntnis die Konfiguration vornehmen und darf keine Syntaxfehler einbauen - da kann man doch im Prinzip direkt PHP-Code schreiben und spart sich das Parsen des XML.

        1. Vererbung [...]

        Vererbung von Klassen ist dann schön, wenn:

        • es mehr als eine erbende Klasse gibt (wenn das mal irgendwann "sein könnte", gilt: YAGNI)

        YAGNI war mir bis gerade auch noch kein Begriff. Wieder mal für alle (laut Wikipedia): "YAGNI steht für “You Ain’t Gonna Need It”, zu deutsch: „Du wirst es nicht brauchen”". Verstanden!

        Die Tatsache, dass dieses "Muster" ein eigenes Akronym bekommen hat, deutet schon darauf hin, dass sich viele Programmierer mehr an der Schönheit der implementierten Features delektierten, damit aber unnötige Komplexität ins Haus holten, und im Endeffekt in Schönheit starben (oder zumindest ihr Projekt).

        YAGNI symbolisiert Verzicht: Keine "kann man bestimmt später mal gut brauchen"-Features, kein "ist architektonisch aber viel besser erweiterbar auf das, was später mal kommen könnte"-Zuckersahnehäubchen. Relevant ist, was aktuell gefordert ist. Das muss erfüllt werden, mehr nicht.

        [...] Die Frage wäre, ob Config_Ini von Config erben muss. Im Zend-Framework wird das gemacht, ich würde es aber nicht als zwingend ansehen.

        Fällt Dir - außer bei DI - ein Fall ein, wo die Vererbung in diesem Fall keinen Sinn machen würde?

        Vererbung führt ja dazu, dass gemeinsamer Code in beiden Klassen verfügbar ist. Wenn ich Zend_Config als Container und Zugriffsmanager verstehe, der mit definiert aufgebauten Arrays gefüttert wird, und Zend_Config_Ini der Einleser für INI-Dateien ist, der genau solche Arrays aufbaut, dann sehe ich erstmal wenig Grund für gemeinsamen Code.

        Auch hier ist wieder das Stichwort "Testbarkeit" ausschlaggebend. Wenn man ein Objekt testen will, dass von ganz allein andere Objekte instanziiert und benutzt, dann kann man das eigentliche Objekt nicht vollständig testen. Denn man muss auch kontrollieren können, ob und wie das zu testende Objekt sein inneres Objekt anspricht. Sowas geht nur, wenn man anstatt des echten inneren Objekts eine Testklasse hineintut, die die Methodenaufrufe registriert und mit vorgefertigten Resultaten antworten kann.

        Sind das die "ominösen Mock-Objekte"?

        Genau. In der PHP-Welt wirst du zwangsläufig auf PHPunit treffen als einzigem verbreiteten Test-Framework, allerdings auf mehr als ein Mock-Objekt-Framework. PHPunit bringt dafür Funktionalität mit, die aber zu Recht kritisiert wird als zu umständlich konfigurierbar.

        Alternative dazu wäre Mockery. Ist noch im Entstehen (Version 0.7.0), setzt zwingend PHP 5.3 voraus, sieht aber von der Mock-Syntax her sehr gut aus.

        - Sven Rautenberg

        1. Hey Sven,

          1. Einzelne Klasse [...]

          WENN ich die Konfiguration in einer einzelnen Klasse ablegen würde, dann darin direkt "eingemauert" als PHP-Code, und nicht von irgendwoher eingelesen. Die Methoden dieser Klasse erlauben dann den Zugriff auf die Werte, und eventuell kann man auch irgendwie umstellen, welche Variante tatsächlich ausgeliefert wird.

          Wäre das nicht vielleicht eine gute Möglichkeit für einen Cache? Also wenn man zum Beispiel eine XML-Konfiguration einliest und die Klasse die Konfiguration anschließend als "reine PHP-Klasse" speichert. So würde man sich ja das parsen sparen - obwohl ich nicht weiß, ob das von der Optimierung her viel ausmacht.

          Die Gegenfrage wäre an dieser Stelle dann: Warum überhaupt erst XML? Das ist vom Format her ja auch nicht wirklich pflegeleicht, man muss mit Sachkenntnis die Konfiguration vornehmen und darf keine Syntaxfehler einbauen - da kann man doch im Prinzip direkt PHP-Code schreiben und spart sich das Parsen des XML.

          durch das "studieren" von ein paar (PHP-)Frameworks hat sich bei mir vielleicht festgesetzt, dass dies ein nötiger und wichtiger Schritt sei - oder besser: INI, XML und Co. sind "state of the art". Deine Gegenfrage bringt mich allerdings zum Nachdenken.

          1. Vererbung [...]

          Vererbung von Klassen ist dann schön, wenn:

          • es mehr als eine erbende Klasse gibt (wenn das mal irgendwann "sein könnte", gilt: YAGNI)

          YAGNI war mir bis gerade auch noch kein Begriff. Wieder mal für alle (laut Wikipedia): "YAGNI steht für “You Ain’t Gonna Need It”, zu deutsch: „Du wirst es nicht brauchen”". Verstanden!

          Die Tatsache, dass dieses "Muster" ein eigenes Akronym bekommen hat, deutet schon darauf hin, dass sich viele Programmierer mehr an der Schönheit der implementierten Features delektierten, damit aber unnötige Komplexität ins Haus holten, und im Endeffekt in Schönheit starben (oder zumindest ihr Projekt).

          YAGNI symbolisiert Verzicht: Keine "kann man bestimmt später mal gut brauchen"-Features, kein "ist architektonisch aber viel besser erweiterbar auf das, was später mal kommen könnte"-Zuckersahnehäubchen. Relevant ist, was aktuell gefordert ist. Das muss erfüllt werden, mehr nicht.

          Ich werde es mir zu Herzen nehmen!

          [...] Die Frage wäre, ob Config_Ini von Config erben muss. Im Zend-Framework wird das gemacht, ich würde es aber nicht als zwingend ansehen.

          Fällt Dir - außer bei DI - ein Fall ein, wo die Vererbung in diesem Fall keinen Sinn machen würde?

          Vererbung führt ja dazu, dass gemeinsamer Code in beiden Klassen verfügbar ist. Wenn ich Zend_Config als Container und Zugriffsmanager verstehe, der mit definiert aufgebauten Arrays gefüttert wird, und Zend_Config_Ini der Einleser für INI-Dateien ist, der genau solche Arrays aufbaut, dann sehe ich erstmal wenig Grund für gemeinsamen Code.

          Das macht natürlich Sinn. Also wäre das ein Fall für eine externe (Einlese-)Klasse, Dependency Injection oder artverwandte Muster?

          Auch hier ist wieder das Stichwort "Testbarkeit" ausschlaggebend. Wenn man ein Objekt testen will, dass von ganz allein andere Objekte instanziiert und benutzt, dann kann man das eigentliche Objekt nicht vollständig testen. Denn man muss auch kontrollieren können, ob und wie das zu testende Objekt sein inneres Objekt anspricht. Sowas geht nur, wenn man anstatt des echten inneren Objekts eine Testklasse hineintut, die die Methodenaufrufe registriert und mit vorgefertigten Resultaten antworten kann.

          Sind das die "ominösen Mock-Objekte"?

          Genau. In der PHP-Welt wirst du zwangsläufig auf PHPunit treffen als einzigem verbreiteten Test-Framework, allerdings auf mehr als ein Mock-Objekt-Framework. PHPunit bringt dafür Funktionalität mit, die aber zu Recht kritisiert wird als zu umständlich konfigurierbar.

          Gut zu wissen, dann werde ich mich damit mal ein bisschen beschäftigen. So wie's aussieht, wird das aber wohl ein bisschen dauern.

          Alternative dazu wäre Mockery. Ist noch im Entstehen (Version 0.7.0), setzt zwingend PHP 5.3 voraus, sieht aber von der Mock-Syntax her sehr gut aus.

          Auch hier danke für den Link. Das wird aber auch erstmal etwas dauern, bis ich mich da eingelesen habe.

          Und auch Dir danke ich wieder mal für Deine tolle Hilfe!

          Gruß, Dennis

      2. Hi!

        [...] Ich habe schon Designs gesehen, in denen ein leeres Interface (keine definierten Methoden) einfach nur "weil man es so macht" definiert und von einer einzigen Klasse implementiert wurde.
        In so nem Fall würde sogar ich mich wundern, was das soll :-)

        Vielleicht ist das wirklich nicht bedacht, vielleicht auch nur ein Versuch, für zukünftige Erweiterungen gewappnet zu sein. Indem man nicht gegen eine Klasse sondern gegen ein Interface programmiert, ist man flexibler. Allerdings ist ein leeres Interface nicht weiter sinnvoll, denn was von einer implementierenden Klasse soll man denn dann durch das Interface garantiert aufrufen können (solange es nicht von einem anderen ein paar Methoden erbt und nur zusätzlich einen konkreteren Namen bereitstellt, nebst der späteren möglichen Erweiterbarkeit)?

        Also vielleicht ist es sowas wie der vorauseilende Gehorsam, der auch für jede Eigenschaft Getter und Setter vorsieht, die nichts weiter als reine Zuweisung und Lesen machen und bei der man YAGNI was anderes brauchen wird.

        Wenn der Konstruktor des Objekts also selbst was instanziiert, dann ist das KEINE Dependency Injection.
        So hat dedlfix das auch erklärt. Ich bin dabei, das umzusetzen. Danke für die Erklärung!

        Man kann da natürlich auch einen zweiten Konstruktor ohne Übernahmeparameter für das DI-Objekt erstellen, der sich ein Default-Objekt selbst erstellt. Das ist dann der im Gegensatz zum anderen ein Nicht-DI-Konstruktor. Der ruft mit dem selbst erstellten Objekt den DI-Konstruktor auf. Man kann dann also beide Wege fahren. Unter PHP gibts ja keine Methodenüberlagerung, also macht man da den DI-Parameter optional (mit null als Default-Wert) und wenn da nichts kommt, erstellt man sich sein Default-Objekt, ansonsten DI. Das ist insofern sinnvoll, wenn man hauptsächlich oder für den Moment nur die eine Klasse geplant hat, trotzdem aber erweiterbar (YAGNI) und - viel wichtiger - testbar bleiben möchte.

        Lo!

        1. Hey dedlfix,

          bin nach einem super Wochenende wieder zu Hause und kann Euch jetzt auch wieder auf Eure Beiträge antworten.

          [...] Ich habe schon Designs gesehen, in denen ein leeres Interface (keine definierten Methoden) einfach nur "weil man es so macht" definiert und von einer einzigen Klasse implementiert wurde.
          In so nem Fall würde sogar ich mich wundern, was das soll :-)

          Vielleicht ist das wirklich nicht bedacht, vielleicht auch nur ein Versuch, für zukünftige Erweiterungen gewappnet zu sein. Indem man nicht gegen eine Klasse sondern gegen ein Interface programmiert, ist man flexibler. Allerdings ist ein leeres Interface nicht weiter sinnvoll, denn was von einer implementierenden Klasse soll man denn dann durch das Interface garantiert aufrufen können (solange es nicht von einem anderen ein paar Methoden erbt und nur zusätzlich einen konkreteren Namen bereitstellt, nebst der späteren möglichen Erweiterbarkeit)?

          Bis gerade dachte ich, ein (vermeintlich) leeres Interface macht überhaupt keinen Sinn. Aber wenn ich das gerade so lese, kann es ja doch Szenarien geben, in denen so etwas Sinn macht. Also wieder eine "kommt auf den Fall an"-Entscheidung? Oder verstehe ich das falsch?

          Wenn der Konstruktor des Objekts also selbst was instanziiert, dann ist das KEINE Dependency Injection.
          So hat dedlfix das auch erklärt. Ich bin dabei, das umzusetzen. Danke für die Erklärung!

          Man kann da natürlich auch einen zweiten Konstruktor ohne Übernahmeparameter für das DI-Objekt erstellen, der sich ein Default-Objekt selbst erstellt. Das ist dann der im Gegensatz zum anderen ein Nicht-DI-Konstruktor. Der ruft mit dem selbst erstellten Objekt den DI-Konstruktor auf. Man kann dann also beide Wege fahren. Unter PHP gibts ja keine Methodenüberlagerung, also macht man da den DI-Parameter optional (mit null als Default-Wert) und wenn da nichts kommt, erstellt man sich sein Default-Objekt, ansonsten DI. Das ist insofern sinnvoll, wenn man hauptsächlich oder für den Moment nur die eine Klasse geplant hat, trotzdem aber erweiterbar (YAGNI) und - viel wichtiger - testbar bleiben möchte.

          Gut, ich glaube, ich hab's jetzt (nach mehreren Ausführungen endlich :-) ) verstanden: DI ist ein gutes Mittel um einer Klasse spezielle Methoden oder Eigenschaften "aufzuprägen", sollte aber durch eine "Standard-Implementation" (was passiert, wenn kein "spezielles Objekt" übergeben wurde?) ergänzt werden. Korrigiert mich bitte, wenn dem nicht so ist. Ansonsten versuche ich, das in Zukunft so zu verwenden.

          Mit großem Dank und Gruß,
          Dennis

          1. Hi!

            Bis gerade dachte ich, ein (vermeintlich) leeres Interface macht überhaupt keinen Sinn. Aber wenn ich das gerade so lese, kann es ja doch Szenarien geben, in denen so etwas Sinn macht. Also wieder eine "kommt auf den Fall an"-Entscheidung? Oder verstehe ich das falsch?

            Wenn ein Interface ganz leer ist, also auch nicht von einem anderen etwas geerbt hat, dann kann man nicht dagegen programmieren. Außer, es bildet die gemeinsame Grundlage für andere Interfaces. Dann kann man zumindest mit instanceof darauf prüfen, muss aber zur konkreten Bedienung dann doch von den Erben wissen, was man da ansprechen kann.

            PHP kennt vordefinierte Interfaces. Eins davon ist Traversable, das leer ist, aber die Grundlage für Iterator und IteratorAggregate bildet. PHP behandelt intern vermutlich die beiden letztgenannten Interfaces separat. Als Programmierer kann man jedoch auf instanceof Traversable prüfen, oder das als Code Hint angeben, um eine Iterierbarkeit eines Objekts festzustellen/festzulegen.

            Gut, ich glaube, ich hab's jetzt (nach mehreren Ausführungen endlich :-) ) verstanden: DI ist ein gutes Mittel um einer Klasse spezielle Methoden oder Eigenschaften "aufzuprägen", sollte aber durch eine "Standard-Implementation" (was passiert, wenn kein "spezielles Objekt" übergeben wurde?) ergänzt werden. Korrigiert mich bitte, wenn dem nicht so ist. Ansonsten versuche ich, das in Zukunft so zu verwenden.

            Einen zusätzlichen Default-Konstruktor, der ein fest vorgegebenes Objekt instantiiert, brauchst du nicht unbedingt. Wenn du richtige DI mit DI-Framework machst, dann ist es eigentlich seine Aufgabe, die Auflösung von Abhängigkeiten sicherzustellen und dafür zu sorgen, dass es ein Fehler ist, wenn für eine Abhängigkeit keine Erfüllungen (weiß grad nicht, ob es dafür einen Fachbegriff gibt) konfiguriert wurden.

            Lo!

            1. Hey dedlfix,

              zuerst einmal eine kleine Info zum aktuellen Stand des ursprünglichen Problems: Nach heutigem Gespräch dürfen wir _vorerst_ auch fertige Komponenten verwenden. Allerdings nur, "wenn dies auch erlaubt ist" (wann es erlaubt ist, konnte nicht beantwortet werden; also heißt es jetzt erstmal "Lizenzen wälzen") und wenn _jede_ Code-Zeile der externen Komponente kommentiert wird. Das ist für uns zwar ein kleiner Fortschritt; der Sinn hinter den Kommentaren erschließt sich mir aber nicht. Ich komme mir grade vor, als ob ich ein PHP-Tutorial schreiben sollte...

              Na gut, genug geweint :-) Gerade DI interessiert mich aber auch unabhängig von der ursprünglichen Frage, nachdem Ihr mir das schmackhaft gemacht habt.

              Bis gerade dachte ich, ein (vermeintlich) leeres Interface macht überhaupt keinen Sinn. Aber wenn ich das gerade so lese, kann es ja doch Szenarien geben, in denen so etwas Sinn macht. Also wieder eine "kommt auf den Fall an"-Entscheidung? Oder verstehe ich das falsch?

              Wenn ein Interface ganz leer ist, also auch nicht von einem anderen etwas geerbt hat, dann kann man nicht dagegen programmieren. Außer, es bildet die gemeinsame Grundlage für andere Interfaces. Dann kann man zumindest mit instanceof darauf prüfen, muss aber zur konkreten Bedienung dann doch von den Erben wissen, was man da ansprechen kann.

              Gut, dann habe ich das richtig verstanden. Hätte es aber auch gern so klar ausgedrückt...

              PHP kennt vordefinierte Interfaces. Eins davon ist Traversable, das leer ist, aber die Grundlage für Iterator und IteratorAggregate bildet. PHP behandelt intern vermutlich die beiden letztgenannten Interfaces separat. Als Programmierer kann man jedoch auf instanceof Traversable prüfen, oder das als Code Hint angeben, um eine Iterierbarkeit eines Objekts festzustellen/festzulegen.

              Sehr gutes, konkretes Beispiel für's Verständnis!

              Gut, ich glaube, ich hab's jetzt (nach mehreren Ausführungen endlich :-) ) verstanden: DI ist ein gutes Mittel um einer Klasse spezielle Methoden oder Eigenschaften "aufzuprägen", sollte aber durch eine "Standard-Implementation" (was passiert, wenn kein "spezielles Objekt" übergeben wurde?) ergänzt werden. Korrigiert mich bitte, wenn dem nicht so ist. Ansonsten versuche ich, das in Zukunft so zu verwenden.

              Einen zusätzlichen Default-Konstruktor, der ein fest vorgegebenes Objekt instantiiert, brauchst du nicht unbedingt. Wenn du richtige DI mit DI-Framework machst, dann ist es eigentlich seine Aufgabe, die Auflösung von Abhängigkeiten sicherzustellen und dafür zu sorgen, dass es ein Fehler ist, wenn für eine Abhängigkeit keine Erfüllungen (weiß grad nicht, ob es dafür einen Fachbegriff gibt) konfiguriert wurden.

              Jetzt weiß ich zumindest, welche Aufgabe unter anderem ein DI-Framework leisten sollte. Aber das alles innerhalb so kurzer Zeit zu verstehen, ist mir zuviel des Guten :-) Ich werd' mich in der nächsten Zeit diesbezüglich mal etwas einlesen und würde mich freuen, wenn Du mir bei vielleicht aufkommenden Fragen weiterhin so toll helfen könntest.
              In einem anderen Post habe ich ja schon den Blog von Fabien Potencier erwähnt. Der hat auch einen Artikel zu DI. Ohne Dir den jetzt komplett durchlesen zu müssen: Hört sich der Artikel vernünftig an, um DI besser zu verstehen?

              Gruß, Dennis

              1. Hi!

                In einem anderen Post habe ich ja schon den Blog von Fabien Potencier erwähnt. Der hat auch einen Artikel zu DI. Ohne Dir den jetzt komplett durchlesen zu müssen: Hört sich der Artikel vernünftig an, um DI besser zu verstehen?

                Nach dem Lesen der ersten zwei Teile denke ich, dass er für das Verständnis von DI sehr hilfreich ist. Er erklärt auch einige Dinge anders, als ich und als es mir geläufig war. Ich muss dazusagen, dass ich bisher nur die von mir als DI-light bezeichnete Variante und kein DI-Framework verwendet hatte. Er bezeichnet das bereits als (vollwertige) DI. Und die Injection geht nicht nur über Konstruktoren, sondern auch über Methoden und Eigenschaften. Hauptsache ist, man übergibt benötigte Komponenten, als dass sich ein Objekt selbst welche holt. Wenn man nicht zu Fuß die Abhängkeiten auflösen will, ist ein Dependency Injection Container der richtige Fachbegriff für den Teil, der weiß, wie konkrete Objekte und ihre Abhängigkeiten zu erzeugen sind. DI-Frameworks gibt es natürlich auch, und das sind dann konkrete Implementation solcher DICs und der benötigten Programmlogik dahinter.

                Ich geh dann mal weiterlernen.

                Lo!

                1. Hey dedlfix,

                  In einem anderen Post habe ich ja schon den Blog von Fabien Potencier erwähnt. Der hat auch einen Artikel zu DI. Ohne Dir den jetzt komplett durchlesen zu müssen: Hört sich der Artikel vernünftig an, um DI besser zu verstehen?

                  Nach dem Lesen der ersten zwei Teile denke ich, dass er für das Verständnis von DI sehr hilfreich ist.

                  danke für die Einschätzung. Dann nehme ich das jetzt erstmal als Grundlage.

                  Er erklärt auch einige Dinge anders, als ich und als es mir geläufig war.

                  Findest Du? Für mich hört sich das fast genauso an wie das, was Du gesagt hast - oder wie ich Dich verstanden hab :-) Einziger Unterschied ist doch, dass ...

                  [...] Und die Injection geht nicht nur über Konstruktoren, sondern auch über Methoden und Eigenschaften. Hauptsache ist, man übergibt benötigte Komponenten, als dass sich ein Objekt selbst welche holt.

                  ... er dies sagt. Allerdings kann ich auch nicht beurteilen, ob das seine alleinige Meinung ist oder ob DI so "definiert" wurde. Sinnvoll hört es sich für mich aber an.

                  Wenn man nicht zu Fuß die Abhängkeiten auflösen will, ist ein Dependency Injection Container der richtige Fachbegriff für den Teil, der weiß, wie konkrete Objekte und ihre Abhängigkeiten zu erzeugen sind. DI-Frameworks gibt es natürlich auch, und das sind dann konkrete Implementation solcher DICs und der benötigten Programmlogik dahinter.

                  Das muss ich mir nochmal genauer ansehen. So ganz erschließt sich mir noch nicht, wie das vonstatten gehen soll. Ok, dass, was ich z.B. in der test.php gemacht hatte:

                    
                  $file = new FileObject('test.ini');  
                    
                  $loadHelper = new LoadHelperIni($file);  
                    
                  $config = new Config();  
                  $config->load($loadHelper);  
                  
                  

                  kann ich natürlich auch in eine Klasse bzw. Klassen-Methode auslagern. Aber wie mich da ein Framework bei unterstützen soll, verstehe ich noch nicht. Außer vielleicht, dass diese Container in einer Registry abgelegt werden, sodass ich von überall aus darauf Zugriff habe.

                  Ich geh dann mal weiterlernen.

                  Das mach ich jetzt auch. Allerdings muss ich jetzt leider wieder der Numerischen Mathematik frönen. In zwei Wochen steht die Klausur an.

                  Gruß, Dennis

                  1. Hi!

                    Er erklärt auch einige Dinge anders, als ich und als es mir geläufig war.
                    Findest Du? Für mich hört sich das fast genauso an wie das, was Du gesagt hast - oder wie ich Dich verstanden hab :-)

                    Nicht grundlegend, aber in Details und Begrifflichkeiten.

                    Einziger Unterschied ist doch, dass ...

                    [...] Und die Injection geht nicht nur über Konstruktoren, sondern auch über Methoden und Eigenschaften. Hauptsache ist, man übergibt benötigte Komponenten, als dass sich ein Objekt selbst welche holt.
                    ... er dies sagt. Allerdings kann ich auch nicht beurteilen, ob das seine alleinige Meinung ist oder ob DI so "definiert" wurde. Sinnvoll hört es sich für mich aber an.

                    Hört sich auch für mich plausibel an. Er hat sich ja mit den Frameworks schon beschäftigt, also wird auch seine Erklärung besser als meine sein.

                    [Dependency Injection Container und DI-Frameworks]
                    Das muss ich mir nochmal genauer ansehen. So ganz erschließt sich mir noch nicht, wie das vonstatten gehen soll. Ok, dass, was ich z.B. in der test.php gemacht hatte:

                    $file = new FileObject('test.ini');

                    $loadHelper = new LoadHelperIni($file);

                    $config = new Config();
                    $config->load($loadHelper);

                      
                    Das ist (entgegen [meiner anderen Aussage](https://forum.selfhtml.org/?t=206131&m=1398955) dann doch) DI in dem Fall handverdrahtet und über eine Methode.  
                      
                    
                    > kann ich natürlich auch in eine Klasse bzw. Klassen-Methode auslagern. Aber wie mich da ein Framework bei unterstützen soll, verstehe ich noch nicht. Außer vielleicht, dass diese Container in einer Registry abgelegt werden, sodass ich von überall aus darauf Zugriff habe.  
                      
                    Für handverdrahtete DI sehe ich bei kleineren bis mittleren Projekten durchaus einen Sinn. Es nützt jetzt nicht übermäßig viel, wenn du keine Flexibilität bei der Abhängigkeitsauflösung benötigst, aber trotzdem ein DI-Framework einsetzt, das auf der einen Seite an deine Objekte angebunden werden muss und als großen Nachteil noch die Parameter, die deine Objekte so brauchen, an einer anderen Stelle konfigurieren musst. Damit hast du dann zwei Baustellen, die deine Aufmerksamkeit als Alleinunterhalter beanspruchen. Anders sieht die Sache im Team aus, wenn sich einer um die DI-Framework-Konfiguration kümmern kann und die anderen nur noch auf einfache Weise benötigte Objekte anfordern müssen.  
                      
                      
                    Lo!
                    
                    1. Hey dedlfix,

                      Er erklärt auch einige Dinge anders, als ich und als es mir geläufig war.
                      Findest Du? Für mich hört sich das fast genauso an wie das, was Du gesagt hast - oder wie ich Dich verstanden hab :-)

                      Nicht grundlegend, aber in Details und Begrifflichkeiten.

                      ist zwar nicht wichtig, bin aber gerade trotz mehrfachen Lesens drüber gestolpert: Meinst Du,
                      er sagt grundlegend das gleiche wie Du, unterscheidet sich aber in Details und Begrifflichkeiten oder
                      er sagt nicht grundlegend das gleiche wie Du, aber Details und Begrifflichkeiten ähneln sich.

                      Ich gehe davon aus Du meintest ersteres.

                      Mir fällt immer wieder auf, was deutsch für eine schöne und differenzierte Sprache ist. Aber ich glaube gerade dadurch kommt es auch häufiger zu Mehrdeutigkeiten.
                      Wo ich das gerade schreibe fällt mir wieder die Geschichte ein, die uns unser Musiklehrer früher (mindestens tausendmal) erzählt hat, um uns klarzumachen, wie wichtig die Betonung in Musik und Sprache ist:
                      Ein Räuber soll gehängt werden und hat einen letzten Wunsch frei. Er wünscht sich der König möge ihn begnadigen. Ein Bote übermittelt dem König den letzten Wunsch und dieser anwortet: "Hängt ihn nicht, laufen lassen!" Der Bote rennt zurück zum Exekutionsplatz und ruft völlig außer Atem: "Hängt ihn, nicht laufen lassen!"

                      Das hat alles nichts mit Deiner Antwort oder dem Thema zu tun. Ist mir nur grad eingefallen und musste es einfach mal kurz niederschreiben :-)

                      Er hat sich ja mit den Frameworks schon beschäftigt, also wird auch seine Erklärung besser als meine sein.

                      "Besser" ist relativ. Seine Erklärung ist vielleicht fachlich genauer, Deine Erklärungen finde ich persönlich aber viel "besser". "Besser" in dem Sinne, dass es für mich verständlicher ist und das ich so mehr lernen kann. Und auch wenn mal was nicht hundertprozentig stimmt, lerne ich gerade dadurch noch mehr. Es gilt ja auch allgemein, dass sich "Fehler" besser einprägen - insbesondere, wenn man sich über Dinge austauscht und diskutiert.
                      Außerdem zeigen solche Tutorials nur allgemeine Wege auf. Deine Antworten beziehen sich aber direkt auf _meine_ Verständnisprobleme.

                      [Dependency Injection Container und DI-Frameworks]
                      Das muss ich mir nochmal genauer ansehen. So ganz erschließt sich mir noch nicht, wie das vonstatten gehen soll. Ok, dass, was ich z.B. in der test.php gemacht hatte [...]
                      kann ich natürlich auch in eine Klasse bzw. Klassen-Methode auslagern. Aber wie mich da ein Framework bei unterstützen soll, verstehe ich noch nicht. Außer vielleicht, dass diese Container in einer Registry abgelegt werden, sodass ich von überall aus darauf Zugriff habe.

                      Für handverdrahtete DI sehe ich bei kleineren bis mittleren Projekten durchaus einen Sinn. Es nützt jetzt nicht übermäßig viel, wenn du keine Flexibilität bei der Abhängigkeitsauflösung benötigst, aber trotzdem ein DI-Framework einsetzt, das auf der einen Seite an deine Objekte angebunden werden muss und als großen Nachteil noch die Parameter, die deine Objekte so brauchen, an einer anderen Stelle konfigurieren musst. Damit hast du dann zwei Baustellen, die deine Aufmerksamkeit als Alleinunterhalter beanspruchen. Anders sieht die Sache im Team aus, wenn sich einer um die DI-Framework-Konfiguration kümmern kann und die anderen nur noch auf einfache Weise benötigte Objekte anfordern müssen.

                      Ok, also werden wir die Container erstmal hinten anstellen, die Objekt-Abhängigkeiten von Hand erstellen und gegen Interfaces implementieren.
                      Und ich werde mich weiter in das Thema einlesen.

                      Aber eine kurze Sache nochmal: Wie kann ich mir denn so ein DI-Framework vorstellen? Oder besser: Welche Vorteile bietet es mir? Ich stelle mir das immernoch so vor, dass ich auch in einem DI-Framework die Objekte von Hand erstellen muss - nur eben nur einmal innerhalb eines solchen Containers. Und anschließend kann ich aus dem gesamten Framework statt einer speziellen Klasse eben diesen Container aufrufen.

                      Gruß, Dennis

                      1. Hi!

                        Meinst Du,
                        er sagt grundlegend das gleiche wie Du, unterscheidet sich aber in Details und Begrifflichkeiten oder
                        er sagt nicht grundlegend das gleiche wie Du, aber Details und Begrifflichkeiten ähneln sich.
                        Ich gehe davon aus Du meintest ersteres.

                        Ja.

                        Aber eine kurze Sache nochmal: Wie kann ich mir denn so ein DI-Framework vorstellen? Oder besser: Welche Vorteile bietet es mir? Ich stelle mir das immernoch so vor, dass ich auch in einem DI-Framework die Objekte von Hand erstellen muss - nur eben nur einmal innerhalb eines solchen Containers. Und anschließend kann ich aus dem gesamten Framework statt einer speziellen Klasse eben diesen Container aufrufen.

                        Deine Anwendung profitiert davon, dass sie nur einen sehr allgemeinen Wunsch äußern muss und nicht haarklein selbst alle für die Abhängigkeiten benötigten Werte zusammentragen und die Objekte in der richtigen Reihenfolge instantiieren muss. Wie auch bei der Verwendung einer stinknormalen Funktion profitiert man davon, wenn solche Aufrufe mehrfach stattfinden oder/und durch die Kapselung der Teilaufgabe zu einer besseren Überschaubarkeit beitragen.

                        Es ist wie immer, jede Vereinfachung erhöht die Komplexität. Sie verschwindet ja nicht, wie man annehmen könnte, sie wird nur verlagert. Und um an den neuen Lagerort zu kommen, braucht man einen Weg, der vorher noch nicht da war, also zusätzlich erschaffen werden muss. Auch bei mehrfacher Verwendung wird die generelle Komplexität nicht weniger, denn der Weg muss beschritten (= Funktionsaufruf und Rückkehr) und die verlagerte Funktionalität ausgeführt werden. Der Vorteil ist "lediglich" eine vereinfachte Notation der Ausführungsanweisung.

                        Und so ist es auch mit dem DI-Container. Als erstes schafft er Übersichtlichkeit bei der aufrufenden Stelle, dann ermöglicht er ein schnelleres Notieren bei weiteren Verwendungen. Aber wenn du mal einen Fehler hast, kann der nicht nur innerhalb des Containers sein, sondern zusätzlich auch noch beim Aufruf und der Werterückgabe liegen. Und beim Beseitigen musst du berücksichtigen, dass es noch eine Menge weiterer Verwender geben kann, die durch eine Änderung betroffen sein können.

                        Lo!

                        1. Hey dedlfix,

                          Aber eine kurze Sache nochmal: Wie kann ich mir denn so ein DI-Framework vorstellen? Oder besser: Welche Vorteile bietet es mir? [...]

                          [...] Und um an den neuen Lagerort zu kommen, braucht man einen Weg, der vorher noch nicht da war, also zusätzlich erschaffen werden muss. [...]

                          Aber wenn du mal einen Fehler hast, kann der nicht nur innerhalb des Containers sein, sondern zusätzlich auch noch beim Aufruf und der Werterückgabe liegen.

                          die beiden Punkte sind genau das, woran ich nicht gedacht hatte. Danke!

                          Gruß, Dennis

  6. Wollte Euch nur kurz sagen, dass ich jetzt am Wochenende unterwegs bin und mir deshalb Eure sicherlich wieder hervorragenden Antworten erst am Montag durchlesen und dann beantworten werde. So "zwischen Tür und Angel" macht das ja keinen Sinn.

    Gruß und schönes Wochenende,
    Dennis

  7. hi,

    Du beschreibst einen Data Abstraction Layer (DAL). Den würde ich als Klasse realisieren, Entwurfsmuster 1 und 2. Du brauchst Scnittstellen, die zwischen einer zentralen Datenhaltung und verteilten Daten vermitteln müssen, das ist Sache des DAL.

    Hotti

    1. Du beschreibst einen Data Abstraction Layer (DAL). Den würde ich als Klasse realisieren, Entwurfsmuster 1 und 2. Du brauchst Scnittstellen, die zwischen einer zentralen Datenhaltung und verteilten Daten vermitteln müssen, das ist Sache des DAL.

      Ergänzung Klassenhierarchie:

      DAL-Baseclass: ORM, sitzt auf einer DB als Data-Layer
      Subklassen:
      ORM::XML, ORM::INI

      Beispiel "ORM::XML::branchin": Methode zum Einbau eines aus XML kommenden Verzeichniszweiges in die zentrale Konfiguration.

      Die Subklassen beschreiben die Umsetzung/Einbau von XML, INI in die Datenstruktur des ORM. Die Application arbeitet mit einer Datenstruktur oder mit Methoden, die von Baseclass ORM bereitgestellt werden.

      Die Application hat Schnittstellen zu XML, INI, diese Schnittstellen bedienen sich der Methoden von ORM::XML, ORM::INI usw.

      Architektur meines CMS, stellt die Position des DAL als Tie-Klasse dar:

      Tie-Klassen

      1. Hey hotti,

        auch Dir vielen Dank für Deine Antwort.

        Du beschreibst einen Data Abstraction Layer (DAL).

        Nach meinem Kenntnisstand und dem Beispiel im Ausgangsposting, grundsätzlich ja.

        Den würde ich als Klasse realisieren,

        Das ist auch so geplant. Allerdings würden ja alle in meinem Ausgangsposting beschriebenen Entwurfsmuster (PHP-)Klassen verwenden, sodass mich interessieren würde, warum Du ...

        Entwurfsmuster 1 und 2.

        ... bevorzugen würdest? Dedlfix und Sven Rautenberg haben mir ja im Verlauf dieses Themas schon gute Begründungen und Erklärungen geliefert, warum insbesondere diese beiden Muster Nachteile mit sich bringen (könnten).

        Du brauchst Scnittstellen, die zwischen einer zentralen Datenhaltung und verteilten Daten vermitteln müssen, das ist Sache des DAL.

        Auch das ist richtig und auch in ähnlicher Form geplant. Allerdings spräche das doch allgemein gegen Muster Nummer 1? Oder hast Du da noch andere Ansätze?

        Ergänzung Klassenhierarchie:

        DAL-Baseclass: ORM, sitzt auf einer DB als Data-Layer
        Subklassen:
        ORM::XML, ORM::INI

        Beispiel "ORM::XML::branchin": Methode zum Einbau eines aus XML kommenden Verzeichniszweiges in die zentrale Konfiguration.

        Die Subklassen beschreiben die Umsetzung/Einbau von XML, INI in die Datenstruktur des ORM. Die Application arbeitet mit einer Datenstruktur oder mit Methoden, die von Baseclass ORM bereitgestellt werden.

        Wenn ich Dich richtig verstehe ist dies Entwurfsmuster 2?

        [...] Architektur meines CMS, stellt die Position des DAL als Tie-Klasse dar:

        Tie-Klassen

        Schöne Übersicht! Allerdings geht's dabei ja um die gesamte Anwendung und nicht um die Frage nach den Entwurfsmustern. Hab mir das Bild mal gespeichert (falls ich darf!?). Finde, das ist eine schöne Übersicht, wie die einzelnen Komponenten zusammenspielen können.

        Gruß, Dennis

        Ps: Du schreibst ja in Perl. Das fand ich persönlich sehr unübersichtlich. Ich möchte keine neue Diskussion "Perl vs. PHP" anzetteln (die gab's ja glaub' ich schon genug), hätte aber eine kurze Frage: Wo liegen _grundsätzlich_ (Syntax ausgenommen!) die Unterschiede zwischen beiden Sprachen? Mir kamen beide vom Umfang her immer relativ ähnlich vor.
        Mit grundsätzlich meine ich beispielsweise: Mehrfachvererbung? Implizite Typumwandlung? usw.

        1. hi Dennis,

          Ps: Du schreibst ja in Perl. Das fand ich persönlich sehr unübersichtlich. Ich möchte keine neue Diskussion "Perl vs. PHP" anzetteln (die gab's ja glaub' ich schon genug), hätte aber eine kurze Frage: Wo liegen _grundsätzlich_ (Syntax ausgenommen!) die Unterschiede zwischen beiden Sprachen? Mir kamen beide vom Umfang her immer relativ ähnlich vor.

          Den wesentlichen Unterschied sehe ich darin: Mit Perl wirds übersichtlicher ;)

          Weitere Vorzüge Perl:

          • Es gibt weniger Abhängigkeiten von der Version
          • seit v5.6.1 Unterstützung UTF-8, wird immer besser

          Mit grundsätzlich meine ich beispielsweise: Mehrfachvererbung? Implizite Typumwandlung? usw.

          • genau dies geht mit Perl hervorragend

          Ich selbst neige jedoch eher zur Delegierung einzelner Methoden, anstelle das Erbe _aller_ Methoden einer Klasse anzutreten.

          OOP -> einheitliche und klar definierte Schnittstellen
          CPAN -> Wahnsinn, was es alles schon gibt ;)
          Design Patterns -> ja klar, da passt Vieles, mein erstes DP war das Transit-State-Model für CGI-Scripts in Perl (ist 10 Jahre her)
          Templates -> Urvater sprintf(), c, Perl
          Und: Tie-Klassen -> Mächtig gewaltig!

          Hotti

          PS: Meine Grafik, ja geht etwas an DP vorbei, es ist mehr die Anwendung.

          --
          Wenn der Kommentar nicht zum Code passt, kann auch der Code falsch sein.
          1. Hey hotti,

            Ps: Du schreibst ja in Perl. Das fand ich persönlich sehr unübersichtlich. Ich möchte keine neue Diskussion "Perl vs. PHP" anzetteln (die gab's ja glaub' ich schon genug), hätte aber eine kurze Frage: Wo liegen _grundsätzlich_ (Syntax ausgenommen!) die Unterschiede zwischen beiden Sprachen? Mir kamen beide vom Umfang her immer relativ ähnlich vor.

            Den wesentlichen Unterschied sehe ich darin: Mit Perl wirds übersichtlicher ;)

            Ich dachte mir schon, dass Du das schreibst :-)

            Weitere Vorzüge Perl:

            • Es gibt weniger Abhängigkeiten von der Version
            • seit v5.6.1 Unterstützung UTF-8, wird immer besser

            Ja, stimmt. Ich hoffe auf PHP 6...

            Mit grundsätzlich meine ich beispielsweise: Mehrfachvererbung? Implizite Typumwandlung? usw.

            • genau dies geht mit Perl hervorragend

            Unterstützt Perl auch implizite Typumwandlung?
            Bezüglich Mehrfachvererbung: Da das grundsätzlich möglich ist könnten dann ja in Perl für das gleiche Problem andere Entwurfsmuster zielführender (eleganter) sein als in PHP. Darauf zielte auch meine Frage ab, um etwas besser einschätzen zu können, warum Du Entwursmuster 1 oder 2 bevorzugst.

            OOP -> einheitliche und klar definierte Schnittstellen

            Siehe oben: Ich hoffe auf die neue PHP-Version.

            CPAN -> Wahnsinn, was es alles schon gibt ;)

            Hab da grad mal ein bisschen getstöbert. Da gibt's echt unglaublich viel.

            Und: Tie-Klassen -> Mächtig gewaltig!

            Hab mich auch da grad mal etwas eingelesen. So wie ich's verstehe bietet das wirklich viele Möglichkeiten. Und ich versteh' jetzt wenigstens mal ein bisschen, worüber Du sprichst, wenn ich Beiträge von Dir lese :-)

            Gruß und danke,
            Dennis

            Ps: Meine Aussage "Mir kamen beide vom Umfang her immer relativ ähnlich vor." nehme ich übrigens zurück. Nach ein bisschen Lesen erscheint mir Perl (noch ;-) )wesentlich offener und umfangreicher als PHP.

          2. Hi!

            Um nur mal zwei rauszupicken:

            Ich selbst neige jedoch eher zur Delegierung einzelner Methoden, anstelle das Erbe _aller_ Methoden einer Klasse anzutreten.

            Ungefähr so wie das Restaurant-Beispiel, wo der Tisch vom Restaurant erbt? Und weil ein Restaurant noch jede Menge Zeugs beinhaltet, das ein Tisch nicht benötigt, selektierst du lieber, anstatt eine ordentliche und sinnvolle Klassenstruktur aufzusetzen?

            Und: Tie-Klassen -> Mächtig gewaltig!

            Und aus Freude, ein Anwendungsprinzip verstanden zu haben, verwendest du es nun so inflationär, dass es mir ungesund erscheint ...

            Lo!

            1. Hey dedlfix,

              Ich selbst neige jedoch eher zur Delegierung einzelner Methoden, anstelle das Erbe _aller_ Methoden einer Klasse anzutreten.

              Ungefähr so wie das Restaurant-Beispiel, wo der Tisch vom Restaurant erbt? Und weil ein Restaurant noch jede Menge Zeugs beinhaltet, das ein Tisch nicht benötigt, selektierst du lieber, anstatt eine ordentliche und sinnvolle Klassenstruktur aufzusetzen?

              interessant... ;-) Jetzt ist auf jeden Fall meine Frage, wie ich die Beiträge einordnen kann, geklärt.

              Gruß, Dennis

        2. hi again,

          Entwurfsmuster 1 und 2.

          ... bevorzugen würdest? Dedlfix und Sven Rautenberg haben mir ja im Verlauf dieses Themas schon gute Begründungen und Erklärungen geliefert, warum insbesondere diese beiden Muster Nachteile mit sich bringen (könnten).

          bischen mehr nun, vorhin war die Zeit etwas knapp...Perl und Data Abstraction Layer:

          • gut zu machen in Perl ist der Wechsel zwischen byte/character Semantics
          • TieKlassen:
            
          tie %bin, 'ORM';  
          print $bin{'/index.html'}{title}; # byte-Semantics  
          # setze Character Semantics, title ist in utf8  
          SvUTF8::utf8(\$bin{'/index.html'}{title});  
          # jetzt liefern alle Stringfunktionen ein zeichenorientiertes Ergebnis  
          # length($bin{'/index.html'}{title}); # Anzahl der Zeichen  
          # substr(), uppercase...  
          # usw...  
          
          

          Tie-Klassen binden eine Variable an eine Klasse. Zeile 2 erzeugt eine DB-Abfrage, die im Hintergrund abläuft. In der Application wird nur mit Datenstrukturen (z.B. Hash) oder Methoden gearbeitet, der Layer 'ORM' ist austauschbar gegen eine Klasse, welche dieselbe Datenstruktur/Methoden liefert.

          Subklassen:
          ORM;
          ORM::XML;
          können alle einer Datei notiert sein. Oder die Subklassen werden in extra Dateien ausgelagert. Perl findet alles ;)

          Hotti

          PS: etwas vom Thema abschweifend, ein Perl-CGI-Script, objektorientiert geschrieben mit Template und automatisierter Parameterkontrolle. Schön zu sehen ist die Delegeirung der Methoden CGI::param und CGI::header ohne _alle_ Methoden von Klasse CGI zu erben:

            
          #!/usr/bin/perl  
            
          # CGI-Script mit Template  
          ###########################################################################  
          use strict;  
          use warnings;  
          use CGI;  
            
          my $u = main->new;  
            
          # auf Parameter prüfen  
          if($u->param){  
          	$u->control;  
          }  
            
          print $u->header, $u->out;  
            
          exit 0;  
          ###########################################################################  
            
          # Parameterkontrolle  
          # suche anhand der Parameterliste eine passende Funktion  
          sub control{  
          	my $self = shift;  
          	foreach my $p($self->param){  
          		if(my $code = $self->can($p)){  
          			$self->$code;  
          			return;  
          		}  
          	}  
          	# Wenn keine passende Methode gefunden wurde, unbekannter Parameter  
          	$self->errpush('Unbekannter Parameter', 'Backbutton und erneut versuchen...');  
          	return;  
          }  
            
          # Fehlerspeicher schreiben bei Bedarf  
          sub errpush{  
          	my $self = shift;  
          	push @{$self->{ERR}}, @_;  
          }  
            
          # Parameter einbauen und Eingaben verarbeiten  
          # Funktion hat denselben Namen wie der Parameter  
          sub produkt{  
          	my $self = shift;  
          	# Eingaben erfassen  
          	my $f1 = $self->param('f1');  
          	my $f2 = $self->param('f2');  
          	if($f1 !~ /^\d+$/){  
          		$self->errpush('Bitte nur ganze Zahlen für Wert 1', 'Backbutton und erneut versuchen...');  
          	}  
          	elsif($f2 !~ /^\d+$/){  
          		$self->errpush('Bitte nur ganze Zahlen für Wert 2', 'Backbutton und erneut versuchen...');  
          	}  
          	else{  
          		$self->{TEMPLVAL} = {  
          			f1 => $f1,  
          			f2 => $f2,  
          			produkt => $f1 * $f2,  
          		};  
          	}  
          }  
            
          # Template (Body) ausgeben  
          # Im Fehlerfall wird eine Fehlerseite ausgegeben  
          sub out{  
          	my $self = shift;  
          	if(scalar @{$self->{ERR}}){  
          		return sprintf "<p>%s</p>", join "</p><p>", @{$self->{ERR}};  
          	}  
          	else{  
          		$self->{TEMPLVAL}->{action} = $ENV{SCRIPT_NAME};  
            
          		# Liste mit den Platzhaltern durchgehen  
          		# wenn Werte anliegen, werden die Platzhalter ersetzt  
          		foreach my $s(@{$self->{TEMPLIST}}){  
          			$s = defined $self->{TEMPLVAL}->{$s} ? $self->{TEMPLVAL}->{$s} : '';  
          		}  
          		return sprintf $self->{TEMPLATE}, @{$self->{TEMPLIST}};  
          	}  
          }  
            
          # Konstruktor main-Object  
          sub new{  
          	my $class = shift;  
          	my $self = bless{  
          		CGI => CGI->new,  
          		TEMPLIST => [],  
          		TEMPLVAL => {},  
          		TEMPLATE => '',  
          		ERR => [],  
          		type => 'text/html',  
          		charset => 'UTF-8',  
          	}, $class;  
          	$self->_template; # Template einbauen  
          	return $self;  
          }  
            
          # Methode erzeugt das Template und legt es ins Objekt  
          # Das Template ist ein Formular  
          sub _template{  
          	my $self = shift;  
          	# Definition der Felder/Platzhalter im Template  
          	$self->{TEMPLIST} = ['action', 'f1', 'f2', 'produkt'];  
          	$self->{TEMPLATE} = qq(  
          		<h2>Ein einfaches Formular</h2>  
          		  
          		<form action="%s">  
          		<fieldset><legend><strong>Faktor 1, Faktor 2 und Enter:</strong></legend>  
          			<input name="f1" value="%s">  
          			<input name="f2" value="%s">  
          			<input name="produkt" value="Bilde das Produkt" type="submit">  
          		</fieldset>  
          		</form>  
          		<p>Ergebnis: %s</p>  
          	);  
          }  
            
          # Delegierung CGI::param  
          sub param{  
          	my $self = shift;  
          	return wantarray ? $self->{CGI}->param(@_) : _trim($self->{CGI}->param(@_));  
          }  
            
          # Delegierung CGI::header  
          sub header{  
          	my $self = shift;  
          	my @args = @_ ? @_ : (-type => $self->{type}, -charset => $self->{charset});  
          	return $self->{CGI}->header(@args);  
          }  
            
          # Entferne Leerzeichen  
          sub _trim{  
          	my $s = shift or return;  
          	$s =~ s/^\s+//; # leading  
          	$s =~ s/\s+$//; # trailing  
          	return $s;  
          }  
          
          
          1. Hey hotti,

            hab mir Deinen Beitrag jetzt mehrfach durchgelesen und bin begeistert - verstehe aber leider fast kein Wort davon... :-)

            Das Skript und Deine Kommentare dazu sehen echt interessant aus, übersteigen meine (zugegebenermaßen mickrigen) Perl-Kenntnisse aber um Weiten.

            Ich lese Deine Beiträge hier im Forum aber weiterhin aufmerksam und werde mich, wenn es die Zeit zulässt, auch mal wieder mit Perl auseinandersetzen. Vielleicht kann ich dann in naher Zukunft auch mal mitreden.

            Ich danke Dir aber auch hier für Deine Mühe und das Beispiel.

            Gruß, Dennis