sven_peters: In nested class auf übergeordnete Klasse zugreifen

Hallo!

Erst mal der Quelltext, der ziemlich sinnlos ist:

class A
{
    public $a;

function __construct()
    {
        $this->a = new B();
    }

function myInstance()
    {
        return get_class();
    }
}

class B
{
    function testB()
    {
        echo 'B.testB()';
        echo '<br>';

echo 'include from: ' . $GLOBALS['a']->myInstance();
    }
}

$a = new A();
$a->a->testB();

Klasse B wird in Klasse A eingebunden. Die Methode a.a.testB() soll ausgeben, von welcher Klasse bzw. auch Instanz sie eingebunden wurde. Die Lösung, auf die konkrete Instanz $GLOBALS['a'] zuzugreifen, kann natürlich nicht als optimal angesehen werden.

Gibt es, ähnlich wie in abgeleiteten Klassen mittels parent, innerhalb der Klasse B eine Möglichkeit, an den Zeiger $a zu kommen, um auf Methoden von Klasse A zurückgreifen zu können?

  1. echo $begrüßung;

    Gibt es, ähnlich wie in abgeleiteten Klassen mittels parent, innerhalb der Klasse B eine Möglichkeit, an den Zeiger $a zu kommen, um auf Methoden von Klasse A zurückgreifen zu können?

    In deinem speziellen Fall hast du genau eine Referenz auf ein Objekt der Klasse B in der Eigenschaft a eines Objekts der Klasse A abgelegt. Es kann aber beliebig viele Referenzen auf diese B-Objekt geben. Herauszufinden, welche Variablen (globale und lokale, inklusive Array-Elementen und Objekteigenschaften) eine Referenzen auf einen bestimmten Variablen-Container darstellen, ist in PHP nicht vorgesehen und sicher auch nicht zu 100% selbst zu erstellen.

    Wenn du einen expliziten Verweis aus dem B-Objekt heraus auf das A-Objekt benötigst, dann muss das B-Objekt sich selbst eine Referenz merken. Die kann man ja beim B-Konstruktoraufruf mit übergeben.

    echo "$verabschiedung $name";

    1. Hallo!

      In deinem speziellen Fall hast du genau eine Referenz auf ein Objekt der Klasse B in der Eigenschaft a eines Objekts der Klasse A abgelegt. Es kann aber beliebig viele Referenzen auf diese B-Objekt geben. Herauszufinden, welche Variablen (globale und lokale, inklusive Array-Elementen und Objekteigenschaften) eine Referenzen auf einen bestimmten Variablen-Container darstellen, ist in PHP nicht vorgesehen und sicher auch nicht zu 100% selbst zu erstellen.

      Das dachte ich mir.

      Ich muß etwas ausholen, könnte aber etwas kompliziert werden. Es geht um ein Pluginsystem. Mehrere Klassen erben von einer Superklasse. In dieser Superklasse ist eine statische Methode definiert, die automatisch aus einem Pluginverzeichnis Plugins ausliest und Unterklassen in die Unterklassen der Superklasse ablegt. Leider habe ich keine Möglichkeit gefunden, Klassen in andere Klassen statisch einzubinden, deswegen werden die Pluginklassen als (Array-)Instanzen in den Unterklassen "inkludiert". Die statische Inkludierungsmethode bekommt den jeweiligen Zeiger der aufrufenden Unterklasse der Superklasse übergeben. Ich habe das jetzt so erweitert, daß diese Methode den Zeiger an die Pluginklasse weiterreicht, wo er als private Eigenschaft $parent abgelegt wird. Somit kann ich zwar jetzt, ohne auf $GLOBALS zurückgreifen zu müssen, relativ frei Instanzen der Unterklassen der Superklasse bilden und in den Pluginklassen auf deren Methoden zugreifen, aber der Weg ist ziemlich vertrackt und nicht gerade wartungsfreundlich.

      Erschwerend kommt noch hinzu, daß es mir absolut nicht möglich ist, die Pluginklassen gleich zu benennen. Wenn ich ein Plugin info habe und für drei Unterklassen denselben Klassennamen Info verwenden will, meckert der PHP-Interpreter, er könne sie nicht redeklarieren. Es ist also nicht eine Kapselung UK1.Info, UK2.Info, UK3.Info usw. möglich, weil die Klassen Info allesamt dem globalen Namensraum angehören. Ich habe mir so beholfen. die drei Pluginklassen UK1_Info, UK2_Info usw. zu benennen, und im Array werden sie trotzdem als UK1.plugin['Info'] benannt, aber das ist aus Sicht der OOP ziemlich schräg.

      Dewegen frage ich noch mal: Ist es tatsächlich nicht möglich, Klassen statisch in andere Klassen einzubinden, ähnlich einer Closure?

      Ich hoffe, ich habe das einigermaßen nachvollziehbar beschrieben.

      1. echo $begrüßung;

        Ich muß etwas ausholen, könnte aber etwas kompliziert werden. [...]

        Und ich konnte dir kaum folgen. Du verwendest ziemlich oft den Begriff Klasse, aber wie mir scheint auch dann, wenn du Objekte meinst. Versuch es verständlich und nachvollziehbar zu beschreiben, denn so kann ich dein Vorhaben nicht bewerten und (alternative) Lösungsvorschläge anbieten.

        Erschwerend kommt noch hinzu, daß es mir absolut nicht möglich ist, die Pluginklassen gleich zu benennen. Wenn ich ein Plugin info habe und für drei Unterklassen denselben Klassennamen Info verwenden will, meckert der PHP-Interpreter, er könne sie nicht redeklarieren.

        Das ist richtig. Klassen und Funktionen lassen sich unter PHP nicht so schachteln, dass sie lokal bleiben. Sie werden immer im globalen Namensraum abgelegt.

        Es ist also nicht eine Kapselung UK1.Info, UK2.Info, UK3.Info usw. möglich, weil die Klassen Info allesamt dem globalen Namensraum angehören.

        Meine vorige Aussage löst sich aber grade teilweise in Wohlgefallen auf, denn PHP 5.3 steht vor der Tür und damit auch Namensräume.

        Dewegen frage ich noch mal: Ist es tatsächlich nicht möglich, Klassen statisch in andere Klassen einzubinden, ähnlich einer Closure?

        Closures gibt derzeit auch nicht, werden aber ebenfalls mit 5.3 eingeführt. Allerdings handelt es sich dabei nur um anonyme Funktionen, nicht um ganze Klassen.

        echo "$verabschiedung $name";

        1. Hallo!

          Ich muß etwas ausholen, könnte aber etwas kompliziert werden. [...]

          Und ich konnte dir kaum folgen.

          Ich habe es befürchtet :(

          »»Du verwendest ziemlich oft den Begriff Klasse, aber wie mir scheint auch dann, wenn du Objekte meinst. Versuch es verständlich und nachvollziehbar zu beschreiben, denn so kann ich dein Vorhaben nicht bewerten und (alternative) Lösungsvorschläge anbieten.

          Ok, noch mal langsam. Es gibt eine Superklasse SK. Es gibt einige Klassen, die von SK ableiten: UK1, UK2 usw. In SK ist eine statische Methode getPlugins($instance) definiert, die von Instanzen von UK1 usw. aufgerufen wird:

          $uk1 = new UK1;

          In UK1 im Konstruktor:
          $this->getPlugins($this);

          In SK.getPlugins() findet sowohl der include() als auch die Instanzenbildung
          $instance->$newInstance = new $class($instance); statt. Es gibt in SK noch eine andere statische Methode, die zuvor eine Liste mit den vorhandenen Plugins erzeugt. Wie zu sehen, reicht getPlugins() mit new $class($instance) den Zeiger weiter, der sodann in dem Plugin gespeichert wird. $newInstance und $class sind im Prinzip nur bereinigte Namen, vgl. das o. g. Problem mit demselbem Namespace.

          Auf die Pluginmethoden läßt sich jetzt mit $uk1->plugin->methode() zugreifen. Im Plugin selbst kann auf Methoden von UK1 zugreifen.

          Schöner wäre es, wenn es nicht nötig wäre, Plugininstanzen mit $instance->$newInstance = new $class($instance); zu bilden, sondern einfach die Pluginklasse als statische Klasse direkt in UK1 einzubinden, um dann von außen mit $uk1->pluginmethode() zugreifen zu können.

          Erschwerend kommt noch hinzu, daß es mir absolut nicht möglich ist, die Pluginklassen gleich zu benennen. Wenn ich ein Plugin info habe und für drei Unterklassen denselben Klassennamen Info verwenden will, meckert der PHP-Interpreter, er könne sie nicht redeklarieren.

          Das ist richtig. Klassen und Funktionen lassen sich unter PHP nicht so schachteln, dass sie lokal bleiben. Sie werden immer im globalen Namensraum abgelegt.

          :(

          Es ist also nicht eine Kapselung UK1.Info, UK2.Info, UK3.Info usw. möglich, weil die Klassen Info allesamt dem globalen Namensraum angehören.

          Meine vorige Aussage löst sich aber grade teilweise in Wohlgefallen auf, denn PHP 5.3 steht vor der Tür und damit auch Namensräume.

          Ja, habe ich auch schon gelesen.

          Ich denke, damit hat sich die Frage nach einer statischen Einkapselung in andere Klasse erledigt.

          Wenn Du aber Vorschläge für eine bessere Architektur hast, sind die auch willkommen.

          1. echo $begrüßung;

            Es gibt eine Superklasse SK.

            Welche Aufgabe hat diese?

            Es gibt einige Klassen, die von SK ableiten: UK1, UK2 usw.

            Und wozu dienen diese? Hast du mehrere Plugin-Stellen in deinem Programm und jeweils eine UK ist für solch eine Stelle zuständig? Und SK ist eine generische Klasse solch einer Plugin-Stelle?

            In SK ist eine statische Methode getPlugins($instance) definiert, die von Instanzen von UK1 usw. aufgerufen wird:
            $uk1 = new UK1;
            In UK1 im Konstruktor:
            $this->getPlugins($this);

            Mit -> ruft man Methoden dynamisch auf. Statische Aufrufe gehen über klassenname::methodenname(…). Bei $this->getPlugins($this); handelt es sich um einen dynamischen Aufruf und es ist überflüssig, $this zu übergeben, denn innerhalb von getPlugins zeigt $this auf dein $uk1.

            In SK.getPlugins() findet sowohl der include() als auch die Instanzenbildung

            Das sind vermutlich die einzelnen Plugins.

            $instance->$newInstance = new $class($instance); statt.

            Ich nehme an, in $class befindet sich der Klassenname des Plugins. Spricht was dagegen, die UKx à la PluginPlatz zu benennen und für die Plugin-Klassen die Namenskonvention PluginPlatz_IndividuellerName zu verwenden?

            Es gibt in SK noch eine andere statische Methode, die zuvor eine Liste mit den vorhandenen Plugins erzeugt. Wie zu sehen, reicht getPlugins() mit new $class($instance) den Zeiger weiter, der sodann in dem Plugin gespeichert wird. $newInstance und $class sind im Prinzip nur bereinigte Namen, vgl. das o. g. Problem mit demselbem Namespace.

            Auf die Pluginmethoden läßt sich jetzt mit $uk1->plugin->methode() zugreifen. Im Plugin selbst kann auf Methoden von UK1 zugreifen.

            Warum muss ein Plugin auf einen Plugin-Handler zugreifen? Um ein Radio zu beschreiben braucht es keinen Verweis auf den Ort an dem es steht. Für unterschiedliche Typen aber eine Klasse anzulegen, die von einer generischen Radioklasse erbt, ist schon eher sinnvoll. So ein Radio braucht zum Arbeiten Instanzen der Klassen Antenne und Lautsprecher. Die sucht es sich aber nicht selbständig aus seiner Umgebung (wofür es einen Verweis auf die Umgebung übergeben benötigte) sondern bekommt sie als Parameter bei der Inbetriebnahme übergeben.

            Schöner wäre es, wenn es nicht nötig wäre, Plugininstanzen mit $instance->$newInstance = new $class($instance); zu bilden, sondern einfach die Pluginklasse als statische Klasse direkt in UK1 einzubinden, um dann von außen mit $uk1->pluginmethode() zugreifen zu können.

            Klassen sind während der Laufzeit statische Dinge. Bereits vor dem Kompilieren müssen ihre Beziehungen zueinander feststehen. Auch wenn wie im Falle PHPs Codeteile auch noch zur Laufzeit hinzugefügt werden können, ändert das nichts an ihren feststehenden Beziehungen zueinander.

            Wenn jemand ein Plugin schreibt, das auf generische Funktionen zugreifen soll, dann kann man eine Plugin-Elternklasse erstellen, von der dann das Plugin erben kann.

            Klassen so zu designen, dass sie viele Dinge von ihrer Umgebung wissen müssen, nach denen sie noch dazu selbständig greifen sollen, ist kein gutes Design. Alles was sie wissen müssen, sollte man ihnen übergeben. Man kann sie besser testen (händisch als auch mit Unit-Tests), wenn man nicht erst eine komplexe Umgebung aufbauen muss. Besser ist es, das Benötigte in Form von Dummys zu übergeben.

            echo "$verabschiedung $name";

            1. Hallo!

              echo $begrüßung;

              Es gibt eine Superklasse SK.

              Welche Aufgabe hat diese?

              Dort sind einige wichtige Eigenschaften und Methoden definiert, die für alle UKs gleich sind.

              Es gibt einige Klassen, die von SK ableiten: UK1, UK2 usw.

              Und wozu dienen diese? Hast du mehrere Plugin-Stellen in deinem Programm und jeweils eine UK ist für solch eine Stelle zuständig? Und SK ist eine generische Klasse solch einer Plugin-Stelle?

              Die UKs sind im Prinzip Verfeinerungen von SK.

              In SK ist eine statische Methode getPlugins($instance) definiert, die von Instanzen von UK1 usw. aufgerufen wird:
              $uk1 = new UK1;
              In UK1 im Konstruktor:
              $this->getPlugins($this);

              Mit -> ruft man Methoden dynamisch auf. Statische Aufrufe gehen über klassenname::methodenname(…). Bei $this->getPlugins($this); handelt es sich um einen dynamischen Aufruf und es ist überflüssig, $this zu übergeben, denn innerhalb von getPlugins zeigt $this auf dein $uk1.

              Nein, genau das geht leider nicht, weil die statische Methode ja instanzenlos aufgerufen wird. Deswegen kann dort kein Zeiger vorhanden sein.

              In SK.getPlugins() findet sowohl der include() als auch die Instanzenbildung

              Das sind vermutlich die einzelnen Plugins.

              $instance->$newInstance = new $class($instance); statt.

              Ich nehme an, in $class befindet sich der Klassenname des Plugins. Spricht was dagegen, die UKx à la PluginPlatz zu benennen und für die Plugin-Klassen die Namenskonvention PluginPlatz_IndividuellerName zu verwenden?

              Ja, genau so habe ich es auch gemacht. $newInstance und $class unterscheiden sich nur durch das Präfix für die aufnehmende UK. In $class ist es vorhanden, in $newInstance nicht mehr:

              'UK1'->'Plugin1' = new 'UK1_Plugin1'('UK1');

              (nur daß statt UK1 Instanzen von UK1 gedacht werden müssen).

              Somit kann das Plugin jetzt sehr fein kreiert werden. Wenn es z. B. Funktionalität zu UK1, UK2 und UK7 hinzufügt, gibt es drei Klassen UK1_Plugin4, UK2_Plugin4, UK7_Plugin4. Ärgerlich ist eben der Zwang zu dem Präfix, aber damit muß und kann ich leben.

              Es gibt in SK noch eine andere statische Methode, die zuvor eine Liste mit den vorhandenen Plugins erzeugt. Wie zu sehen, reicht getPlugins() mit new $class($instance) den Zeiger weiter, der sodann in dem Plugin gespeichert wird. $newInstance und $class sind im Prinzip nur bereinigte Namen, vgl. das o. g. Problem mit demselbem Namespace.

              Auf die Pluginmethoden läßt sich jetzt mit $uk1->plugin->methode() zugreifen. Im Plugin selbst kann auf Methoden von UK1 zugreifen.

              Warum muss ein Plugin auf einen Plugin-Handler zugreifen? Um ein Radio zu beschreiben braucht es keinen Verweis auf den Ort an dem es steht. Für unterschiedliche Typen aber eine Klasse anzulegen, die von einer generischen Radioklasse erbt, ist schon eher sinnvoll. So ein Radio braucht zum Arbeiten Instanzen der Klassen Antenne und Lautsprecher. Die sucht es sich aber nicht selbständig aus seiner Umgebung (wofür es einen Verweis auf die Umgebung übergeben benötigte) sondern bekommt sie als Parameter bei der Inbetriebnahme übergeben.

              Ok, ich weiß nicht, ob ich Dich richtig verstehe. Man könnte natürlich auch bei Methodenaufrufen der eingeschachtelten Klasse jeweils einen Zeiger auf eine Instanz einer anderen Klasse mit übergeben, damit es dessen Methoden nutzen kann. Das wäre zwar auch eine Möglichkeit, aber ich denke, so wie es jetzt ist, mit einmaliger Übergabe bei Instanzierung ist es für meine Zwecke einfacher.

              Schöner wäre es, wenn es nicht nötig wäre, Plugininstanzen mit $instance->$newInstance = new $class($instance); zu bilden, sondern einfach die Pluginklasse als statische Klasse direkt in UK1 einzubinden, um dann von außen mit $uk1->pluginmethode() zugreifen zu können.

              Klassen sind während der Laufzeit statische Dinge. Bereits vor dem Kompilieren müssen ihre Beziehungen zueinander feststehen. Auch wenn wie im Falle PHPs Codeteile auch noch zur Laufzeit hinzugefügt werden können, ändert das nichts an ihren feststehenden Beziehungen zueinander.

              Wenn jemand ein Plugin schreibt, das auf generische Funktionen zugreifen soll, dann kann man eine Plugin-Elternklasse erstellen, von der dann das Plugin erben kann.

              In den UKs sind halt wichtige Methoden und Eigenschaften wie DB-Verbindungen, die für das Plugin vorhanden sein müssen. Es wäre natürlich klasse, wenn man den Zugriff wie bei der Vererbung mittels protected und private steuern könnte. Als anderes Design könnte ich mir noch vorstellen, Dinge, auf die ein Plugin Zugriff haben soll, als weiteres eingeschachteltes Objekt abzubilden und hierauf einen Zeiger zu übergeben, aber das ändert ja nichts an dem architektonischen Konzept.

              Das alles ginge natürlich theoretisch, wenn, wie von Dir angeregt, das Plugin selbst von UK erbt. Das Problem ist aber, daß vor Benutzung von Pluginmethoden schon eine Instanz von UK vorhanden ist. Das Plugin müßte deswegen nicht nur die Struktur von UK erben, sondern den konkreten Inhalt von der UK-Instanz. Für alle diese Inhalte nun Schnittstellen nach außen zu erstellen, mittels denen dann das Plugin die Inhalte abrufen kann, mag zwar sauberer, dafür aber auch um ein Vielfaches aufwendiger sein, als wenn einfach eine Nested Class zu einer Instanz von UK hinzugefügt wird.

              Klassen so zu designen, dass sie viele Dinge von ihrer Umgebung wissen müssen, nach denen sie noch dazu selbständig greifen sollen, ist kein gutes Design. Alles was sie wissen müssen, sollte man ihnen übergeben. Man kann sie besser testen (händisch als auch mit Unit-Tests), wenn man nicht erst eine komplexe Umgebung aufbauen muss. Besser ist es, das Benötigte in Form von Dummys zu übergeben.

              Siehe oben.

              1. echo $begrüßung;

                Die UKs sind im Prinzip Verfeinerungen von SK.

                Im Grunde sollen also die UKs Plugin-Handler darstellen. Meiner meinung nach sollte deren Aufgabe nur sein, die Plugins passend durch die Gegend zu wirbeln, ihnen Aufgaben geben und deren Ergebnis entgegenzunehmen. Ihre Aufgabe sollte es jedoch nicht sein, dem Plugin selbst Basisfunktionalität zu bieten. Mir scheint, dass du nicht genügend spezialisierst.

                $this->getPlugins($this);
                Mit -> ruft man Methoden dynamisch auf. Statische Aufrufe gehen über klassenname::methodenname(…). Bei $this->getPlugins($this); handelt es sich um einen dynamischen Aufruf und es ist überflüssig, $this zu übergeben, denn innerhalb von getPlugins zeigt $this auf dein $uk1.
                Nein, genau das geht leider nicht, weil die statische Methode ja instanzenlos aufgerufen wird. Deswegen kann dort kein Zeiger vorhanden sein.

                Du hast aber keinen statischen sondern einen dynamischen Aufruf notiert. Statisch sähe so aus:

                self::getPlugins($this);

                Warum muss ein Plugin auf einen Plugin-Handler zugreifen? [...]
                Ok, ich weiß nicht, ob ich Dich richtig verstehe. Man könnte natürlich auch bei Methodenaufrufen der eingeschachtelten Klasse jeweils einen Zeiger auf eine Instanz einer anderen Klasse mit übergeben, damit es dessen Methoden nutzen kann.

                Warum muss ein Plugin die Methoden eines Plugin-Handlers nutzen? Der Plugin-Handler ist keine Basis für Plugins selbst. Grundlegende Plugin-Funktionalität sollte eine Plugin-Superklasse, oder gegebenenfalls eine auf eine bestimmte Stöpsel-Stelle spezialisierte Superklasse bereitstellen.

                Das wäre zwar auch eine Möglichkeit, aber ich denke, so wie es jetzt ist, mit einmaliger Übergabe bei Instanzierung ist es für meine Zwecke einfacher.

                Vielleicht derzeit. Plane lieber richtig. Aber gut, am besten lernt man aus selbst gemachten Fehlern :-)

                Hier brech ich erstmal ab, weil ich weg muss. Zum Rest äußer ich mich später.

                echo "$verabschiedung $name";

              2. echo $begrüßung;

                Hier also die Fortsetzung von https://forum.selfhtml.org/?t=177683&m=1170861.

                Es gibt eine Superklasse SK.
                Welche Aufgabe hat diese?
                Dort sind einige wichtige Eigenschaften und Methoden definiert, die für alle UKs gleich sind.
                Es gibt einige Klassen, die von SK ableiten: UK1, UK2 usw.
                Und wozu dienen diese? [...]
                Die UKs sind im Prinzip Verfeinerungen von SK.

                Das ist die übliche generische Aufgabe von Super- und abgeleiteten Klassen. Mich hatte eher die Aufgabe aus Geschäftslogik-Sicht interessiert. Meine Vermutungen zu ihrem Tätigkeitsfeld hast du nicht direkt bestätigt oder korrigiert. Ich gehe also davon aus, dass ich damit nicht verkehrt liege.

                Wenn jemand ein Plugin schreibt, das auf generische Funktionen zugreifen soll, dann kann man eine Plugin-Elternklasse erstellen, von der dann das Plugin erben kann.
                In den UKs sind halt wichtige Methoden und Eigenschaften wie DB-Verbindungen, die für das Plugin vorhanden sein müssen. Es wäre natürlich klasse, wenn man den Zugriff wie bei der Vererbung mittels protected und private steuern könnte. Als anderes Design könnte ich mir noch vorstellen, Dinge, auf die ein Plugin Zugriff haben soll, als weiteres eingeschachteltes Objekt abzubilden und hierauf einen Zeiger zu übergeben, aber das ändert ja nichts an dem architektonischen Konzept.

                Wenn die Plugins so gestaltet sind, dass sie selbständig nach Dingen suchen, die sie benötigen, baust du eine Zwei-Wege-Abhängigkeit ein, wie sie in der starken Form nicht unbedingt nötig ist. Nicht nur, dass der Handler mit den Plugins umgehen können muss, auch die Plugins sind direkt abhängig von bestimmten Strukturen ihrer Umgebung. Wenn das Plugin sich die DB-Verbindung sucht, und du die mal später ändern willst, rennst du durch alle Plugins und korrigierst den DB-Verbindungssuchmechanismus. Wenn der Handler die Instanz übergibt, behält der die Kontrolle über die DB-Verbindung und das Plugin. Je mehr du etwas mit der Umgebung verzahnst, desto weniger wiederverwendbar sind die einzelnen Teile.

                Allerdings ist die Praxis manchmal anders als das Ideal. Wenn das Plugin alles übergeben bekommt, dann ist es in seiner Kreativität eingeschränkt. Greift es zu sehr auf die Umgebung zu, ist es die Beweglichkeit, die darunter leidet. Hier muss man Kompromisse schließen. Beispielsweise wird gern als eine wichtige Eigenschaft einer DB-Abstraktionsschicht angeführt, mit geringstem Aufwand das DBMS wechseln zu können. Doch wann hat man dies nötig? Vermutlich nicht mal in 1% der Fälle. Und wenn man dies vorhat, muss man sich in der Verwendung von Leistungsmerkmalen des DBMS stark einschränken auf das was alle können oder was die DB-Abstraktion generalisiert.

                Worauf ich hinauswill: Kompromisse sind oft notwendig. Die bestmöglichen zwischen allen Beteiligten zu finden ist nicht einfach aber auch nicht unwichtig.

                Das alles ginge natürlich theoretisch, wenn, wie von Dir angeregt, das Plugin selbst von UK erbt.

                Nein, ich versuchte anzuregen, es soll von einer Plugin-Klasse erben, nicht von einer Plugin-Handler-Klasse.

                Das Zend Framwork ist zwar nicht das Maß aller Dinge, aber darin steckt viel Erfahrung, von der man gut lernen kann. Das Plugin-System ist dort in der Controller-Komponente untergebracht. Nicht der Controller steuert die Plugins, dafür gibt es den Plugin-Broker. Und der bildet _nicht_ die Basis für die Plugins, dafür existiert die Klasse Zend_Controller_Plugin_Abstract. Allerdings ist das ZF ein Framework für unterschiedliche Aufgaben. Das Plugin-System ist damit auch recht allgemein gehalten. Das Framwork weiß ja nicht, wofür es später mal eingesetzt werden soll, kann also die Plugins nicht mit mehr versorgen als dem Request- und dem Response-Objekt.

                Wenn man als Anwender nun seinen Plugins generell DB-Zugriff gewähren will, würde ich das Plugin_Abstract beerben und ihm zumindest eine Eigenschaft für die DB-Instanz hinzufügen. Der Broker bekäme die zusätzliche Aufgabe die DB-Instanz an die Plugins zu übergeben. Und der Controller muss so spezialisert werden, dass er den neuen Plugin-Broker verwendet, was aber mit einem überschriebenen Konstruktor erledigt ist.

                echo "$verabschiedung $name";

                1. Hallo!

                  Wenn jemand ein Plugin schreibt, das auf generische Funktionen zugreifen soll, dann kann man eine Plugin-Elternklasse erstellen, von der dann das Plugin erben kann.

                  Wenn die Plugins so gestaltet sind, dass sie selbständig nach Dingen suchen, die sie benötigen, baust du eine Zwei-Wege-Abhängigkeit ein, wie sie in der starken Form nicht unbedingt nötig ist. Nicht nur, dass der Handler mit den Plugins umgehen können muss, auch die Plugins sind direkt abhängig von bestimmten Strukturen ihrer Umgebung. Wenn das Plugin sich die DB-Verbindung sucht, und du die mal später ändern willst, rennst du durch alle Plugins und korrigierst den DB-Verbindungssuchmechanismus. Wenn der Handler die Instanz übergibt, behält der die Kontrolle über die DB-Verbindung und das Plugin. Je mehr du etwas mit der Umgebung verzahnst, desto weniger wiederverwendbar sind die einzelnen Teile.

                  Ja, diese Abhängigkeit sehe ich ja auch. Es sind nun leider mehrere Komponenten der einschachtelnden Instanz, die in den Plugins verwendet werden sollen. Wenn es nun nur um die DB-Verbindung ginge, könnte ich eine eigene Methode zur Herstellung implementieren, in der sich die vorhandene der einbindenden Klasse geholt wird. So könnte man bei Bedarf schnell den Mechanismus zur Herstellung einer DB-Verbindung in der Pluginklasse austauschen, wobei auch hier zunächst mal ein Zeiger auf die einbindende Instanz übergeben werden müßte. Aber es sind nun mal auch sehr essentielle Methoden der einbindenden Klasse, die dem Plugin zur Verfügung stehen sollen. Wenn ich nun noch eine Super-Pluginklasse als Zwischenschicht erstelle, sehe ich nicht, welche Verbesserung das bringen könnte außer einem Anstieg der Bürokratie.

                  Eine Möglichkeit, die ich hierin erahne, ist, auf die Übergabe der Instanz an die Pluginklasse zu verzichten, indem bei Einbindung des Plugins die Eigenschaften, z. B. die DB-Verbindung, an die Pluginsuperklasse statisch oder eine Instanz von ihr übergeben wird, auf der dann die eigentliche Pluginklasse operieren kann. Ist es das, worauf Du hinauswillst? Was ist aber mit essentiellen Methoden der einschachtelnden Instanz? Die kann ich ja schlecht alle an die Plugin-SK übergeben bzw., was wäre damit gewonnen?

                  Allerdings ist die Praxis manchmal anders als das Ideal. Wenn das Plugin alles übergeben bekommt, dann ist es in seiner Kreativität eingeschränkt. Greift es zu sehr auf die Umgebung zu, ist es die Beweglichkeit, die darunter leidet. Hier muss man Kompromisse schließen. Beispielsweise wird gern als eine wichtige Eigenschaft einer DB-Abstraktionsschicht angeführt, mit geringstem Aufwand das DBMS wechseln zu können. Doch wann hat man dies nötig? Vermutlich nicht mal in 1% der Fälle. Und wenn man dies vorhat, muss man sich in der Verwendung von Leistungsmerkmalen des DBMS stark einschränken auf das was alle können oder was die DB-Abstraktion generalisiert.

                  Korrekt, das übliche Postulat zur "reinen" OOP sehe ich auch oft als reinen Selbstzweck an.

                  Worauf ich hinauswill: Kompromisse sind oft notwendig. Die bestmöglichen zwischen allen Beteiligten zu finden ist nicht einfach aber auch nicht unwichtig.

                  Das alles ginge natürlich theoretisch, wenn, wie von Dir angeregt, das Plugin selbst von UK erbt.

                  Nein, ich versuchte anzuregen, es soll von einer Plugin-Klasse erben, nicht von einer Plugin-Handler-Klasse.

                  Ich fürchte, ich verstehe Dich in diesem Punkt nicht richtig, oder aber es würde nur eine Zwischenschicht ohne wirklichen praktischen Zweck hinzugefügt.

                  Das Zend Framwork ist zwar nicht das Maß aller Dinge, aber darin steckt viel Erfahrung, von der man gut lernen kann. Das Plugin-System ist dort in der Controller-Komponente untergebracht. Nicht der Controller steuert die Plugins, dafür gibt es den Plugin-Broker. Und der bildet _nicht_ die Basis für die Plugins, dafür existiert die Klasse Zend_Controller_Plugin_Abstract. Allerdings ist das ZF ein Framework für unterschiedliche Aufgaben. Das Plugin-System ist damit auch recht allgemein gehalten. Das Framwork weiß ja nicht, wofür es später mal eingesetzt werden soll, kann also die Plugins nicht mit mehr versorgen als dem Request- und dem Response-Objekt.

                  Das hört sich auf jeden Fall sehr interesant an. Ich werde mir das in Ruhe anschauen.

                  Wenn man als Anwender nun seinen Plugins generell DB-Zugriff gewähren will, würde ich das Plugin_Abstract beerben und ihm zumindest eine Eigenschaft für die DB-Instanz hinzufügen. Der Broker bekäme die zusätzliche Aufgabe die DB-Instanz an die Plugins zu übergeben. Und der Controller muss so spezialisert werden, dass er den neuen Plugin-Broker verwendet, was aber mit einem überschriebenen Konstruktor erledigt ist.

                  Ui, das ist erst mal heftig. Kannst Du das anhand eines fiktiven Beispiels noch mal für mich nachvollziehbarer beschreiben? Das könnte durchaus in die Richtung gehen, die ich brauche.

                  1. echo $begrüßung;

                    Wenn ich nun noch eine Super-Pluginklasse als Zwischenschicht erstelle, sehe ich nicht, welche Verbesserung das bringen könnte außer einem Anstieg der Bürokratie.

                    Je größer ein Unternehmen wird, desto mehr müssen sich die Angestellten spezialisieren. Sie haben dann auch alle Hände mit ihrer Aufgabe zu tun. Einen Spezielisten auszutauschen ist verhältnismäßig einfach gegenüber einem Allrounder, bei dem man aufpassen muss, dass er alle Aufgaben gleich gut erfüllen kann.

                    Eine Möglichkeit, die ich hierin erahne, ist, auf die Übergabe der Instanz an die Pluginklasse zu verzichten, indem bei Einbindung des Plugins die Eigenschaften, z. B. die DB-Verbindung, an die Pluginsuperklasse statisch oder eine Instanz von ihr übergeben wird, auf der dann die eigentliche Pluginklasse operieren kann. Ist es das, worauf Du hinauswillst? Was ist aber mit essentiellen Methoden der einschachtelnden Instanz? Die kann ich ja schlecht alle an die Plugin-SK übergeben bzw., was wäre damit gewonnen?

                    Spezialisierung. Der Broker bekommt vom Controller gesagt: Wir haben jetzt Zustand X. Der Broker sagt all seinen Plugins: Arbeitet jetzt für Zustand X. Dazu gibt er ihnen das was sie dazu vielleicht benötigen und holt die Ergebnisse ab. Die Plugins arbeiten selbständig. Wenn es Arbeitsabläufe gibt, die alle gleichermaßen nutzen sollen/können, dann erben sie das von der Superklasse. Im Büro müssten stattdessen alle auf Schulung. Sie "betteln" jedenfalls nicht ihren Vorarbeiter an, ob er ihnen mal was erledigen kann.

                    Ich fürchte, ich verstehe Dich in diesem Punkt nicht richtig, oder aber es würde nur eine Zwischenschicht ohne wirklichen praktischen Zweck hinzugefügt.

                    Der Vorteil an der Spezialisierung ist die Trennung nach Aufgaben und eine leichtere Wartbarkeit jedes einzelnen Teiles. Eierlegende Wollmilchsäue liefern zwar viel, aber man hat damit auch jede Menge Arbeit.

                    Wenn man als Anwender nun seinen Plugins generell DB-Zugriff gewähren will, würde ich das Plugin_Abstract beerben und ihm zumindest eine Eigenschaft für die DB-Instanz hinzufügen. Der Broker bekäme die zusätzliche Aufgabe die DB-Instanz an die Plugins zu übergeben. Und der Controller muss so spezialisert werden, dass er den neuen Plugin-Broker verwendet, was aber mit einem überschriebenen Konstruktor erledigt ist.
                    Ui, das ist erst mal heftig. Kannst Du das anhand eines fiktiven Beispiels noch mal für mich nachvollziehbarer beschreiben? Das könnte durchaus in die Richtung gehen, die ich brauche.

                    Hier die drei Erweiterungen gegenüber den ZF-Klassen:

                    class My_Plugin_Abstract extends Zend_Controller_Plugin_Abstract {  
                      protected $db;  
                      
                      public function setDb($db) {  
                        $this->db = $db;  
                      }  
                    }  
                      
                    class My_Plugin_Broker extends Zend_Controller_Plugin_Broker {  
                      private $db;  
                      
                      public function setDb($db) {  
                        $this->db = $db;  
                      }  
                      
                      // überschreiben der originalen Methode  
                      public function registerPlugin(My_Plugin_Abstract $plugin, $stackIndex = null) {  
                        Zend_Controller_Plugin_Broker::registerPlugin($plugin, $stackIndex);  
                        $plugin->setDB($db);  
                      }  
                    }  
                      
                    class My_Controller_Front extends Zend_Controller_Front {  
                      public function __construct() {  
                        // damit wird My…Broker geladen und nicht der originale  
                        $this->_plugins = new My_Plugin_Broker();  
                        $this->_plugins->setDb(wo_auch_immer_die_db_instanz_herkommt);  
                      }  
                    }
                    

                    Die Plugins werden über die Controller-Instanz registriert, die die eigentliche Registrierung jedoch an die Broker-Instanz weiterreicht.

                    $front = Zend_Controller_Front::getInstance();  
                    $front->setControllerDirectory('/path/to/controllers')  
                          ->registerPlugin(new MyPlugin());
                    

                    Man könnte auch den Broker aus der Weiterreichung der DB-Instanz raushalten und diese dem Plugin gleich bei der Instantiierung übergeben. Eine andere Idee ist, die Übergabe abhängig vom Wert einer Klassenkonstanten des Plugins zu machen. Vielleicht braucht ja nicht jedes Plugin DB-Zugriff. Oder aber man erweitert den Broker so, dass er beim Registrieren nur den Klassennamen entgegennimmt und er sich um Instanttierung und Durchreichung von benötigten Objekten anhand der Klassenkonstanten-Werte kümmert.

                    echo "$verabschiedung $name";