MB: Nutzen der Interzeptermethoden im Framework

Moin Community,

welchen Nutzen hat es Interzeptormethoden außer __construct() in einem Framework zuverwenden? Es verwundert mich, weil ja eine Klasse in einer gute konzipierte Klassenstruktur in einem Framework weis was sie machen soll.

vlg MB

  1. Was sind denn Interzeptormethoden? ... ok, ich habs grad gefunden es war nur der Begriff.

    Der Nutzen besteht darin dass man damit Code auslagern kann, der erst dann compiliert wird wenn der zur Laufzeit später gebraucht wird. Insgesamt wird der Code damit auch übersichtlicher.

    Ein weiterer Vorteil des Auslagern von Methoden besteht darin, dass diese Methoden in allen Klassenerweiterungen verfügbar sind ohne dass hierzu die Superklasse geändert werden muss. Außerdem werden damit auch Coderedundanhzen vermieden. MfG

  2. Hallo MB,

    die magic methods von PHP sind GERADE in Frameworks interessant, weil PHP keine Möglichkeit hat, einer Klasse Methoden oder Eigenschaften zur Laufzeit hinzuzufügen. JavaScript kann mal eben die Methode foo() an ein Objekt anhängen, in C# gibt's die ExpandoObjects, in PHP musst Du die Interzeptoren nutzen.

    Wenn also ein Framework ein Objekt bereitstellen will, das in bestimmten Kontexten "maßgeschneiderte" Methoden und Properties hat, geht es nicht anders.

    Rolf

    --
    Dosen sind silbern
    1. Wenn also ein Framework ein Objekt bereitstellen will, das in bestimmten Kontexten "maßgeschneiderte" Methoden und Properties hat, geht es nicht anders.

      Interessant in diesem Zusammenhang ist Aggregation bzw. Lazy Delegation (weiter unten im Artikel). So hab ich sämtliche Methoden meiner Factory ausgelagert. MfG

    2. Hi RolfB

      die magic methods von PHP sind GERADE in Frameworks interessant, weil PHP keine Möglichkeit hat, einer Klasse Methoden oder Eigenschaften zur Laufzeit hinzuzufügen.

      oO echt? Ich dachte das ging nich oder ich hab unbewusst gemacht.

      JavaScript kann mal eben die Methode foo() an ein Objekt anhängen

      Mit Prototype?

      in PHP musst Du die Interzeptoren nutzen.

      Werd konkreter ich steh voll kommen auf dem Schlauch am bester bitte mit Anwendungsbeispielen. Du führst regie. Bin gespannt

      vlg MB

      1. Tach!

        die magic methods von PHP sind GERADE in Frameworks interessant, weil PHP keine Möglichkeit hat, einer Klasse Methoden oder Eigenschaften zur Laufzeit hinzuzufügen.

        Man kann zwar Objektvariablen anonyme Funktionen zuweisen, diese aber dann nicht direkt aufrufen. Über den __call()-Umweg solles dann aber wohl doch gehen.

        JavaScript kann mal eben die Methode foo() an ein Objekt anhängen

        Mit Prototype?

        Nicht nur, auch direkt Instanz-Variablen kann man anonyme Funktionen zuweisen.

        let x = {};
        x.foo = function() {...};
        x.foo();
        

        dedlfix.

        1. Moin dedlfix,

          Man kann zwar Objektvariablen anonyme Funktionen zuweisen, diese aber dann nicht direkt aufrufen. Über den __call()-Umweg solles dann aber wohl doch gehen.

          Und wie? Ich kenne die Funktion von __call(). Wie kann man in PHP eine Methode in eine Klasse zur laufzeit mit dieser Interzeptermethode implementieren?

          JavaScript kann mal eben die Methode foo() an ein Objekt anhängen

          Mit Prototype?

          Nicht nur, auch direkt Instanz-Variablen kann man anonyme Funktionen zuweisen.

          Ja ich glaube das hast du unteranderem mir erklärt. Hier das resultat einer spielerei Showcase.

          1. Tach!

            Man kann zwar Objektvariablen anonyme Funktionen zuweisen, diese aber dann nicht direkt aufrufen. Über den __call()-Umweg solles dann aber wohl doch gehen.

            Und wie? Ich kenne die Funktion von __call(). Wie kann man in PHP eine Methode in eine Klasse zur laufzeit mit dieser Interzeptermethode implementieren?

            Implementieren sagt man bei Interfaces. Klassen kann man zur Laufzeit nicht mehr erweitern. Man hat nur das __call(), mit dem man auf einen Aufruf einer nicht vorhandenen Methoden reagieren kann, und damit so tun kann, als ob da was da wäre. Das kommt am Ende auf dasselbe raus.

            dedlfix.

          2. Hallo MB,

            das geht indirekt. Beispiel:

            class DynamicClass {
                private $dynMeth = [];
                public function define($name, callable $implementation)
                {
                   $this->dynMeth[$name] = $implementation;
                }
                public function __call($name, $arguments) 
                {
                    if (isset($this->dynMeth[$name]))
                    {
                       return call_user_func_array($this->dynMeth[$name], $arguments);
                    }
                    // else fail spectacularly
                }
            }
            
            $c = new DynamicClass();
            $c->define("hugo", function($a,$b) { return $a*$b; });
            
            echo $c->hugo(3,4); // -> 12
            

            Natürlich kann das Methoden-Array auch innerhalb der Klasse befüllt werden...

            In dem Zusammenhang gerade gesehen: Es gibt in PHP sogar Funktoren, also Objekte, die man wie eine Funktion aufrufen kann. Dazu überschreibt man die __invoke magic method :)

            Rolf

            --
            Dosen sind silbern
            1. hi Rolf,

              echt sehr schönes beispiel für die Funktion. Danke Dafür.

              Was mich zu der frage bringt was für einen nutzen das hat? Ich vermute mal einen sehr speziellen Nutzen keinen allgemeinen wie dedlfix trefflich gesagt hat oder?

              vlg MB

              1. Hallo MB,

                ein Beispiel für eine Anwendung wäre ein Service-Proxy, der an Hand der WSDL automatisch die Methoden des Services bereitstellt. Die Implementierung verpackt die Parameter dann nur noch in die Seifenkiste oder in einen JSON String und ruft den Service auf.

                Rolf

                --
                Dosen sind silbern
  3. Tach!

    welchen Nutzen hat es Interzeptormethoden außer __construct() in einem Framework zuverwenden?

    Ob Nutzen oder nicht hängt vom Anwendungsfall ab. Eine pauschale Antwort darauf wird dich wohl eher nicht wesentlich erhellen.

    Es verwundert mich, weil ja eine Klasse in einer gute konzipierte Klassenstruktur in einem Framework weis was sie machen soll.

    Und sie soll sich dabei auf ihre eigentliche Arbeit konzentrieren. Bei C# nennt man die Dinger Attribute. Solche verwendet man zum Beispiel bei ASP.NET MVC, um den Controller oder dessen Attribute mit Angaben zur Berechtigung zu versehen. Es kann nicht Aufgabe des Controllers sein, erst zu seinem Aufruf festzustellen, dass der Anwender die Funktionalität gar nicht ausführen darf. Und vor allem, dass da nicht ständig derselbe Prüf-Code in die Actions kopiert werden muss. Deshalb annotiert man den Controller oder einzelne Actions mit Attributen, die angeben, wer zugreifen darf. Der Router, der den passenden Controller nebst Action heraussucht, kann nun anhand dieser Meta-Angaben in den Attributen herausfinden, ob der aktuelle Anwender berechtigt ist, und kann dann den Aufruf durchführen oder ablehnen.

    Weitere Anwendungen sind zum Beispiel im Entity Framework zu finden. Zu deinen Datenklassen werden Metainformationen benötigt, wie Label-Text beim Anzeigen, welche Validatoren verwendet werden sollen oder auch welcher konkrete Datentyp im DBMS auf eine bestimmte Eigenschaft deiner Datenklasse gemapt werden soll. Nicht immer ist es eindeutig wie bei string vs. varchar. Die Datenklasse bleibt in sich selbst sauber, aber die Verwendern können aus den Attributen die Metainformationen entnehmen.

    dedlfix.

    1. Deshalb annotiert man den Controller oder einzelne Actions mit Attributen, die angeben, wer zugreifen darf.

      Kann man machen. Z.B. so

      if( $self->param('delete') ){
          $self->auth() or return;
          # ab hier liegt die Bestätigung
          # der Berechtigung vor
      }
      

      Wobei auf die Attribute, z.B. der Name des Realm oder der Name der Passwortdatei nur in der Methode auth() zugegriffen wird. Die Attribute selbst sind außerhalb vom Code konfigurierbar und schließlicch ist auth() eine Methode die nur bei Bedarf, also erst wenn sie aufgerufen wird, kompiliert wird.

      Aber noch besser ist es, den Code völlig frei und unabhängig von Berechtigungen zu haben. Was sich dann auch in den Namen der Klassen zeigt like Admin::Article, Public::Article

      MfG

      1. Tach!

        Deshalb annotiert man den Controller oder einzelne Actions mit Attributen, die angeben, wer zugreifen darf.

        Kann man machen. Z.B. so

        if( $self->param('delete') ){
            $self->auth() or return;
            # ab hier liegt die Bestätigung
            # der Berechtigung vor
        }
        

        Nee, mit Perl-Code kommt man bei C# nicht weit. Ich kann auch nicht viel mit einzelnen Codeschnipseln eines nicht öffentlich verfügbaren Frameworks einer mir nicht geläufigen Sprache anfangen. Ich kann nicht erkennen, ob das innerhalb eines Controller oder sonstwo stattfindet.

        [Authorize(Roles = "Admin, CanDoSomething")]
        public ActionResult DoSomething(string oneParameter) {
          // ...
        }
        

        Dabei sieht man jedenfalls keinerlei Code, der sich mit dem Prüfen der Berechtigung beschäftigt. Die für die Action nebensächliche Geschichte spiegelt sich lediglich in der Annotation wider.

        dedlfix.

        1. Ich kann nicht erkennen, ob das innerhalb eines Controller oder sonstwo stattfindet.

          Kein Problem, ich sags Dir: Ja. if(param) heißt ja, dass der Controller aufgerufen wird, denn wenn keine Parameter im Request sind, wird der Controller gar nicht gebraucht. MfG

    2. Tach!

      welchen Nutzen hat es Interzeptormethoden außer __construct() in einem Framework zuverwenden?

      Ob Nutzen oder nicht hängt vom Anwendungsfall ab. Eine pauschale Antwort darauf wird dich wohl eher nicht wesentlich erhellen.

      Dass es bei der Frage wohl speziell um PHP geht, habe ich zunächst nicht bemerkt. Wer liest schon das Kleingedruckte in den Posting-Tags?

      PHP hat jedenfalls nicht solche Möglichkeiten, wie objektorientierte Sprachen wie C#. Annotationen hinzufügen ist da nicht so ohne weiteres möglich. Eines der für PHP erhältlichen ORMs verwendet gar Annoationen als Kommentare und parst den Code extra noch mal, um an diese zu gelangen. Eine andere Vorgehensweise wäre anhand der Magic Methods in Methodenaufrufe reinzugrätschen. Der Code dazu muss dabei aber auch in der Klasse oder einer Superklasse notiert sein, ist also direkter Bestandteil und nicht getrennt. Artfremden wiederverwendbaren Code könnte man eher noch mit Traits (anderenorts als Mixin bekannt) realisieren.

      dedlfix.

    3. Moin dedlfix

      welchen Nutzen hat es Interzeptormethoden außer __construct() in einem Framework zuverwenden?

      Ob Nutzen oder nicht hängt vom Anwendungsfall ab. Eine pauschale Antwort darauf wird dich wohl eher nicht wesentlich erhellen.

      Da hast du recht. Vielmehr interessiert es mich welche Interzeptormethoden in welchem Anwendungfall stecken. Ich bin fürn paar Beispiele Dankbar. Da es um Frameworks geht, ist mir ein konzeptioneller Entwurf sehr zweckmäßig und hilfreich, wie man Interzeptormethoden verwenden kann.

      Deshalb annotiert man den Controller oder einzelne Actions mit Attributen, die angeben, wer zugreifen darf.

      Ich kenne den Begriff Annotationen jedoch bezogen auf diesen Kontext weis ich nicht wasgemeint ist. Ich dachte eine Allgemeine Definition ist die nachstehende Funktion kommentieren oder?

      Der Router, der den passenden Controller nebst Action heraussucht, kann nun anhand dieser Meta-Angaben in den Attributen herausfinden, ob der aktuelle Anwender berechtigt ist, und kann dann den Aufruf durchführen oder ablehnen.

      Was sin Meta-Angaben? Ich kenne diesen Begriff nur im allgemeinen und im HTML-Kontext

      vlg MB

      1. Tach!

        Deshalb annotiert man den Controller oder einzelne Actions mit Attributen, die angeben, wer zugreifen darf.

        Ich kenne den Begriff Annotationen jedoch bezogen auf diesen Kontext weis ich nicht wasgemeint ist.

        Vergiss das mal im Zusammenhang mit Interceptoren, das war wohl nicht richtig.

        Ich dachte eine Allgemeine Definition ist die nachstehende Funktion kommentieren oder?

        Annotationen/Attibute sind nicht nur Zierde oder Erklärung, sie erfüllen auch eine Aufgabe.

        Der Router, der den passenden Controller nebst Action heraussucht, kann nun anhand dieser Meta-Angaben in den Attributen herausfinden, ob der aktuelle Anwender berechtigt ist, und kann dann den Aufruf durchführen oder ablehnen.

        Was sin Meta-Angaben? Ich kenne diesen Begriff nur im allgemeinen und im HTML-Kontext

        Meta-Daten sind Daten über die eigentlichen Daten. Meta-Angaben in HTML erzählen etwas zum HTML-Dokument. Beispielsweise ist die Angabe zur Kodierung kein Inhalt eines HTML-Dokuments, man braucht aber diese zusätzliche Information, um es korrekt lesen zu können.

        Wer auf eine Controller-Action zugreifen darf ist keine Information, die die Action zum Erfüllen des eigentlichen Zwecks braucht, man braucht das aber im Zusammenhang mit dieser Action, um steuern zu können, ob der Aufruf durchgeführt werden darf oder nicht.

        dedlfix.

        1. Moin dedlfix,

          Vergiss das mal im Zusammenhang mit Interceptoren, das war wohl nicht richtig.

          ja ein mmarginaler aber entscheidender definitionsfehler meinerseits. Dank für die Aufklärung! Also Magic Method!

          Ich dachte eine Allgemeine Definition ist die nachstehende Funktion kommentieren oder?

          Annotationen/Attibute sind nicht nur Zierde oder Erklärung, sie erfüllen auch eine Aufgabe.

          Also Zierde sind sie ganz sicherlich nicht. Ich orientiere mich sehr stark an @Tags ohne Erklärung zu lesen. Denn die sind sehrt oft selbst erklärend. Aus meinersicht eine geschänk des Himmels.

          Wer auf eine Controller-Action zugreifen darf ist keine Information, die die Action zum Erfüllen des eigentlichen Zwecks braucht, man braucht das aber im Zusammenhang mit dieser Action, um steuern zu können, ob der Aufruf durchgeführt werden darf oder nicht.

          Also du verwendest den Begriff in diesem Kontext allgemein? Den dann habe ich dich in deinem Kommentar diesbezüglich verstenden. Ich wollte nur sichergehen 😉.

          vlg MB

    4. Tach!

      welchen Nutzen hat es Interzeptormethoden außer __construct() in einem Framework zuverwenden? Es verwundert mich, weil ja eine Klasse in einer gute konzipierte Klassenstruktur in einem Framework weis was sie machen soll.

      Und sie soll sich dabei auf ihre eigentliche Arbeit konzentrieren. Bei C# nennt man die Dinger Attribute.

      Ich glaube, das war so nicht richtig. Es war nur das erstbeste Suchergebnis, das ich zu interceptor methods gefunden hatte und da hat man viel mit Attributen/Annotationen hantiert, was mich auf die falsche Fährte führte. Diese Annotationen waren da aber eigentlich nur Hilfsmittel.

      Wenn ich jetzt nicht wieder danebenliege, sind Interceptoren nur dazwischengeschobene Programmteile, die noch irgendwas tun, bevor der eigentliche Aufruf stattfindet oder die etwas mit dem Ergebnis tun, bevor es zum Aufrufer zurückgeht.

      Bei MVC kann man das verwenden, um die eigentliche Arbeit der Controller/Actions um Funktionalität zu ergänzen. Zum Beispiel kann man in die erzeugte Response CORS-Header hinzufügen, die der Browser zwar braucht, die hinzuzufügen aber keine direkte Aufgabe des Controllers ist. Der Aufruf des Controllers wird vom Interceptor abgefangen und der ergänzt die CORS-Header.

      dedlfix.

      1. Hallo dedlfix,

        du kannst die __call Methode nicht als generischen Method Interceptor nutzen, wie es Dir zum Beispiel in C# eine DI-Library wie Unity liefert. Grund ist, dass __call nur gerufen wird, wenn eine unbekannte Methode angesprochen wird.

        Du musst das dann schon explizit vorsehen, also so:

        class Dings {
           function __call($name, $args) {
              Logger::LogCall("Dings", $name, "Enter method");
        
              call_user_func_array([$this, "_".$name], $args);
        
              Logger::LogCall("Dings", $name, "Exit method");
           }
        
           private function _foo($a, $b)
           {
              return $a + $b;
           }
        }
        
        $d = new Dings();
        $d->foo(3,4);     // Ruft via __call die _foo Methode auf
        

        Damit bremst Du PHP allerdings gründlich aus, das darf man nicht mit der Gießkanne machen. Es sei denn, in PHP 7 haben die Kollegen um RL gewaltig optimiert.

        Einen echten Interceptor wollte mal jemand bauen, das scheint aber stecken geblieben zu sein.

        Rolf

        --
        Dosen sind silbern