Ankündigung

Einklappen
Keine Ankündigung bisher.

Eventhandler mit PHP5

Einklappen

Neue Werbung 2019

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Eventhandler mit PHP5

    Guten Morgen

    Ich hab mir heute mal darüber Gedanken gemacht, wie man Events in PHP bauen könnte. Natürlich gibt es schon viele Umsetzungen in etlichen Frameworks (PEAR, ...). Ich würde euch gern meine Umsetzung zeigen und wissen, wie ihr die findet.


    Der Eventhandler selbst:
    PHP-Code:
    <?php

    class EventHandler {

        const 
    REGEX_VALID_EVENT_NAME '/^[a-zA-Z][a-zA-Z0-9]*$/';

        private 
    $arr_events = array();

        public function 
    addEvent($pstr_event$pcb_callback) {

            if ( 
    is_callable($pcb_callback) !== true ) {

                throw new 
    InvalidArgumentException(
                    
    'Der angegebene Callback ist nicht gültig!');

            }

            if ( !
    is_string($pstr_event)
                OR 
    preg_match(self::REGEX_VALID_EVENT_NAME$pstr_event) === ) {

                throw new 
    InvalidArgumentException(
                    
    'Der angegebene Eventname ist ungültig!');

            }

            
    $this->arr_events[$pstr_event][] = $pcb_callback;

        }

        public function 
    bindEvents(array $arr_events$pcb_callback) {

            foreach ( 
    $arr_events as $str_event ) {

                
    $this->addEvent($str_event$pcb_callback);

            }

        }

        public function 
    triggerEvent($pstr_event$obj_subject null, array $parr_params = array()) {

            if ( 
    is_string($pstr_event) ) {

                if ( isset(
    $this->arr_events[$pstr_event]) ) {

                    foreach ( 
    $this->arr_events[$pstr_event] as $cb_callback ) {

                        
    $arr_params = array($obj_subject$parr_params);

                        
    call_user_func_array($cb_callback$arr_params);

                    }

                }

            } else {

                throw new 
    InvalidArgumentException(
                    
    'Eventname muss vom Datentyp "String" sein!');

            }

        }

    }

    ?>
    Der EventHandler im Einsatz:
    PHP-Code:
    class Person {

        private 
    $str_name;
        private 
    $obj_eventhandler;

        public function 
    __construct($pobj_eventhandler$pstr_name) {

            
    $this->str_name $pstr_name;
            
    $this->obj_eventhandler $pobj_eventhandler;

            
    $this->obj_eventhandler->addEvent('onSpeak', array($this'listen'));

        }

        public function 
    speak() {

            echo 
    $this->str_name ' fragt: "Wer ist da?"<br />';

            
    $this->obj_eventhandler->triggerEvent('onSpeak'$this);

        }

        public function 
    listen($obj_subject$parr_params) {

            if ( 
    $obj_subject !== $this ) {

                echo 
    $this->str_name ' antwortet: "Ich!"<br />';

            }

        }

    }

    $obj_eventhandler = new EventHandler();

    $obj_fips = new Person($obj_eventhandler'Fips');
    $obj_alex = new Person($obj_eventhandler'Alex');
    $obj_michi = new Person($obj_eventhandler'Michi');
    $obj_sandra = new Person($obj_eventhandler'Sandra');
    $obj_alexa = new Person($obj_eventhandler'Alexa');

    $obj_fips->speak(); 
    Die Ausgabe:
    Code:
    Fips fragt: "Wer ist da?"
    Alex antwortet: "Ich!"
    Michi antwortet: "Ich!"
    Sandra antwortet: "Ich!"
    Alexa antwortet: "Ich!"
    Ich selbst find die ganze sache SEHR nice, Objekte können somit miteinander kommunizieren, ohne dass sie voneinander wissen

    nja, das wars auch schon,

    Mfg Fips.

  • #2
    Objekte können somit miteinander kommunizieren, ohne dass sie voneinander wissen
    Möglicherweise bringe ich das gerade durcheinander aber... ab PHP 5.4 gibt es doch diese Traits. Geht das nicht auch in die Richtung?
    http://www.php.net/manual/de/language.oop5.traits.php

    Kommentar


    • #3
      Nein. Traits sind laut PHP Website im Endeffekt nur Copy&Paste von Methoden und Eigenschaften. Dadurch ist keine Kommunikation gewährleistet, vielmehr ist es Quelltextminimierung.
      Duch einen EventHandler ist es vielmehr möglich, Objekte über ein Event, das von einem anderem Objekt getriggert wird, zu benachrichtigen. Du kannst dir das ganz einfach wie bei JQuery vorstellen. Du kannst einem div-Element z.B. ein click-Event setzen. Alle Funktionen, die du dann mit dem Event verknüpfst sind dem eigentlichen div-Element nicht bekannt. Sobald der div geklickt wird, triggert dieser nur das Event. Und das Event ist dann die eigentliche Ausführung aller verknüpften Methoden, die als Parameter das div-Element zur weiteren Verarbeitung übergeben bekommen.
      Ziel der Events ist also die Überwachung und Kommunikation, sowie die Erweiterbarkeit von Objekten, ohne direkt die eigentliche Klasse umschreiben zu müssen.

      In PHP wäre übrigens die Syntax für eine Eventanbindung wie bei jQuery möglich:

      PHP-Code:
      $obj_form->onSubmit(function($pobj_subject) {

          
      $pobj_subject->setMessage('Dieses Formular wurde abgeschickt');

      }); 
      EDIT:

      Um das mit meiner EventHandler Klasse nochmal zu verdeutlichen: Die Funktionsweise ist eigentlich ganz einfach, man sieht das sehr schön an folgendem Roh-Beispiel:

      PHP-Code:
      // Neuen Eventhandler anlegen
      $obj_eventhandler = new EventHandler();

      // Neues Event anbinden
      $obj_eventhandler->addEvent('onTest', function() {

          echo 
      "onTest Methode 1<br />";

      });

      // Neues Event anbinden
      $obj_eventhandler->addEvent('onTest', function() {

          echo 
      "onTest Methode 2<br />";

      });

      // Neues Event anbinden
      $obj_eventhandler->addEvent('onFoo', function() {

          echo 
      "onFoo Methode 1<br />";

      });

      // Dieser Aufruf triggert nun das "onTest"-Event. Alle verknüpften Funktionen
      // werden nun nacheinander aufgerufen.
      $obj_eventhandler->triggerEvent('onTest'); 
      Ausgabe demnach:
      Code:
      onTest Methode 1
      onTest Methode 2
      Mfg Fips.

      Kommentar


      • #4
        Ich habe Kritik an Deiner Person

        - Der Eventhandler-Parameter sollte ein Type-Hint bekommen.
        - Das Eventbinding sollte außerhalb der Klasse geschehen.

        also
        PHP-Code:
        $evntMngr = new EventHandler ;

        // Redner
        $fips = new  Person ('Fips' $evntMngr);
        $ursula = new  Person ('Ursula' $evntMngr);

        // Publikum
        $betti = new  Person ('Betty' , new DummyEventHandler);
        $franz = new  Person ('Franz' , new DummyEventHandler);

        $evntMngr->addEvent ('onSpeak' , array ($betti 'listen'));
        $evntMngr->addEvent ('onSpeak' , array ($franz 'listen')); 
        PS:

        $arr_params = array($obj_subject, $parr_params);
        finde ich auch unpraktisch. Warum kein array_merge? Zusätzlich würde ich dann vielleicht für alle Handlerfunktionen auch ein Type-Hint auf den ersten Parameter für ein EventTrigger-Interface einrichten.
        [COLOR="#F5F5FF"]--[/COLOR]
        [COLOR="Gray"][SIZE="6"][FONT="Georgia"][B]^^ O.O[/B][/FONT] [/SIZE]
        „Emoticons machen einen Beitrag etwas freundlicher. Deine wirken zwar fachlich richtig sein, aber meist ziemlich uninteressant.
        [URL="http://www.php.de/javascript-ajax-und-mehr/107400-draggable-sorttable-setattribute.html#post788799"][B]Wenn man nur Text sieht, haben viele junge Entwickler keine interesse, diese stumpfen Texte zu lesen.“[/B][/URL][/COLOR]
        [COLOR="#F5F5FF"]
        --[/COLOR]

        Kommentar


        • #5
          nja, die Person Klasse war nur ein kleines Beispiel, ausserdem hab ich das Beispiel um 4 in der Früh schnell hinprogrammiert xD
          Bei meinem Beispiel wäre der EventHandler im übertragenen Sinne das Kommunikationsmedium der Personen. Find ich eigentlich so nicht schlecht. Natürlich kommt es immer drauf an, wo man den Eventhandler einsetzt, in meinem Beispiel wär das für mich vollkommen valide. Jede Person ist Sender und Empfänger und je nach Kommunikationsmedium (=je nach Instanz des EventHandlers) können die Personen untereinander kommunizieren.

          PS.: Über Intrefaces hab ich mir jez mal noch keine Gedanken gemacht. Es ging mir erstmal rein um die Klasse.

          Kommentar


          • #6
            Das bedeutet aber, dass jede Person immer alles hört. Es sei denn Du verwendest 2 Manager. Was aber wiederum nicht geht, weil Du die Bindings in der Person vornimmst.
            Das widerspricht meines Erachtens der Publish/Subscribe-Logik, die hier doch sinnvoll wäre.
            [COLOR="#F5F5FF"]--[/COLOR]
            [COLOR="Gray"][SIZE="6"][FONT="Georgia"][B]^^ O.O[/B][/FONT] [/SIZE]
            „Emoticons machen einen Beitrag etwas freundlicher. Deine wirken zwar fachlich richtig sein, aber meist ziemlich uninteressant.
            [URL="http://www.php.de/javascript-ajax-und-mehr/107400-draggable-sorttable-setattribute.html#post788799"][B]Wenn man nur Text sieht, haben viele junge Entwickler keine interesse, diese stumpfen Texte zu lesen.“[/B][/URL][/COLOR]
            [COLOR="#F5F5FF"]
            --[/COLOR]

            Kommentar


            • #7
              Ich glaube, PHP ist für so was die falsche Sprache.

              Keine Threads, keine Nutzerinteraktion, keine nennenswerte Laufzeit, keine Frontend-Komponente, …

              Es gibt praktisch keine Statusveränderungen (doof für das Observer pattern). Werte werden einmal berechnet und sind dann oftmals für den Scriptdurchlauf unveränderlich. Wir machen in PHP ja nicht mal echtes MVC, weil unsere Views nicht auf Änderungen im Model reagieren können.

              Wahrscheinlich ist die Chance, dass ein PHP-Script sowieso mit anderen Parametern neu aufgerufen wird, größer als die, dass sich ein zweiter „Event-Listener“ irgendwo zuschalten möchte.

              Klar kann man drüber reden, aber so prädestiniert ist PHP dafür nicht.

              „Hook“ wäre wohl noch ein Stichwort.

              Kommentar


              • #8
                Zitat von mermshaus Beitrag anzeigen
                Ich glaube, PHP ist für so was die falsche Sprache.

                Keine Threads, keine Nutzerinteraktion, keine nennenswerte Laufzeit, keine Frontend-Komponente, …

                Es gibt praktisch keine Statusveränderungen (doof für das Observer pattern). Werte werden einmal berechnet und sind dann oftmals für den Scriptdurchlauf unveränderlich. Wir machen in PHP ja nicht mal echtes MVC, weil unsere Views nicht auf Änderungen im Model reagieren können.

                Wahrscheinlich ist die Chance, dass ein PHP-Script sowieso mit anderen Parametern neu aufgerufen wird, größer als die, dass sich ein zweiter „Event-Listener“ irgendwo zuschalten möchte.

                Klar kann man drüber reden, aber so prädestiniert ist PHP dafür nicht.

                „Hook“ wäre wohl noch ein Stichwort.
                PHP unter Android Entwickler und PHP-GTK Entwickler ( samt Unter-Communities: Winbinder & Co ) werden dir jetzt sagen: Du hast keine Ahnung.

                PHP@android:
                - Threads, Thread Interkommunikation
                - Nutzer-Interaktionen
                - Infinite Runtime
                - in PHP erzeugt: Frontend / Backend

                PHP-GTK inherits PHP@android
                [URL="https://gitter.im/php-de/chat?utm_source=share-link&utm_medium=link&utm_campaign=share-link"]PHP.de Gitter.im Chat[/URL] - [URL="https://raindrop.io/user/32178"]Meine öffentlichen Bookmarks[/URL] ← Ich habe dir geholfen ? [B][URL="https://www.amazon.de/gp/wishlist/348FHGUZWTNL0"]Beschenk mich[/URL][/B].

                Kommentar


                • #9
                  Die Events, die hier angesprochen werden, sind eher Objektkommunikation als geworfene Events. Und die kann sehr wohl Sinn machen, weil Du damit modellieren kannst. Im obigen Beispiel bräuchtest Du alternativ einen PersonenManager, der alle Personen beinhaltet und zusätzlich noch die Information ablegt, wer was empfängt, wenn wer etwas sagt. Die Methoden müsste man dann auch noch hinterlegen, also warum sollte man nicht gleich einen Callback-Manager verwenden?

                  Allgemein Entkopplung und Definition von Erweiterungsschnittstellen (Hooks) sind typische Anwendungsszenarien.
                  [COLOR="#F5F5FF"]--[/COLOR]
                  [COLOR="Gray"][SIZE="6"][FONT="Georgia"][B]^^ O.O[/B][/FONT] [/SIZE]
                  „Emoticons machen einen Beitrag etwas freundlicher. Deine wirken zwar fachlich richtig sein, aber meist ziemlich uninteressant.
                  [URL="http://www.php.de/javascript-ajax-und-mehr/107400-draggable-sorttable-setattribute.html#post788799"][B]Wenn man nur Text sieht, haben viele junge Entwickler keine interesse, diese stumpfen Texte zu lesen.“[/B][/URL][/COLOR]
                  [COLOR="#F5F5FF"]
                  --[/COLOR]

                  Kommentar


                  • #10
                    Job. Eventhandling macht in PHP durchaus Sinn. Die Erweiterbarkeit steigt enorm, ohne andere Klassen ändern zu müssen und somit die Stabilität zu beeinträchtigen. Vom Softwaredesign ist Eventhandling auch durchaus ein Muss. Die Kopplung von Klassen ist durch Eventhandling bis zu einem gewissen grad gewährleistet.

                    Mfg Fips.

                    Kommentar


                    • #11
                      Zitat von acetox94
                      Vom Softwaredesign ist Eventhandling auch durchaus ein Muss.
                      Ich bleibe dabei, dass das auf PHP eher weniger zutrifft.

                      Das hängt vor allem damit zusammen, dass ein PHP-Script eine einzige, innerhalb des Scriptablaufs unveränderliche (ausgegeben ist ausgegeben) Rückgabe generiert, die eine „diskrete” Momentaufnahme von Zuständen darstellt.

                      Es besteht dabei keine Notwendigkeit, dieses Ausgabe kontinuierlich während der Laufzeit zusammenzubauen, weil sie sowieso am Ende in einem Schwung ausgegeben wird.

                      Übertragen auf das Beispiel mit den Personen oben: Es spielt in aller Regel wohl keine Rolle, ob die Personen jeden Satz einzeln hören oder ob sie am Ende einen Buffer mit allen gesagten Sätzen übergeben bekommen. Denn bereits beim Scriptaufruf ist sehr genau definiert, welchen Umfang die fertige Ausgabe haben wird.

                      In der Regel werden einige Listener bei einem Model registriert, dann wird am Model eine Methode aufgerufen, die die Listener informiert, dann ist der Request komplett und das Script beendet. Beim nächsten Request müssen die Listener dann erst wieder neu registriert werden. Listener registrieren, eine Runde Benachrichtigungen, Listener registrieren, eine Runde Benachrichtigungen, …

                      Das kann man machen. Das ist auch wahrscheinlich vom Design her gut.

                      Meiner Meinung nach funktioniert das Prinzip bei Sprachen mit kontinuierlicher „Laufzeit“ (JavaScript) aber um Längen besser. Ein Objektgraph muss nur einmal erzeugt werden und kann dann beliebig viele Events verarbeiten. Bei PHP ist das allein durch die Request/Response-Natur erschwert.

                      Wie im vorherigen Post erwähnt: Ein Beispiel dafür ist die oftmals „verkappte“ MVC-Umsetzung in PHP, bei der eine View nicht ein Model belauscht, sondern vom Controller die Rückgabedaten des Models explizit gesetzt bekommt.

                      Kommentar


                      • #12
                        PHP ist nicht auf Request and Response Environment limitiert, es ist eine Ausführungsumgebung von vielen, mermshaus. Das einzigste Argument bei dem ich dir zustimmen würde ist das PHP ursprünglich für ebendsolches gedacht war. Selbst Infinitive Runtimes sehen in PHP genauso aus wie bspw. in C. Nur das ich mir in PHP nicht für jedes Programm includes in den Source nageln muss für Language-Basics.

                        Code:
                        #include <stdio.h>
                        
                        // main loop, the compiler cares for its startup
                        int main( int argc, const char* argv[] )
                        {
                           while ( true ) {
                        
                           }
                        }
                        PHP-Code:
                        // main loop function
                        function main$argc$argv ) {
                           while ( 
                        true ) {

                           }
                        }

                        // there is no compiler which cares for its startup
                        main($_SERVER['argc'], $_SERVER['argv']); 
                        [URL="https://gitter.im/php-de/chat?utm_source=share-link&utm_medium=link&utm_campaign=share-link"]PHP.de Gitter.im Chat[/URL] - [URL="https://raindrop.io/user/32178"]Meine öffentlichen Bookmarks[/URL] ← Ich habe dir geholfen ? [B][URL="https://www.amazon.de/gp/wishlist/348FHGUZWTNL0"]Beschenk mich[/URL][/B].

                        Kommentar


                        • #13
                          Ich weiß – wie schon beim ersten diesbezüglichen Post – nicht, was ich darauf antworten soll.

                          Wenn in diesem Forum nicht explizit eine andere Variante angesprochen wird, gehe ich immer von der Standardnutzung von PHP aus, ohne mich ausdrücklich gegen alle Eventualitäten abzusichern.

                          Kommentar


                          • #14
                            Zitat von mermshaus Beitrag anzeigen
                            Ich weiß – wie schon beim ersten diesbezüglichen Post – nicht, was ich darauf antworten soll.

                            Wenn in diesem Forum nicht explizit eine andere Variante angesprochen wird, gehe ich immer von der Standardnutzung von PHP aus, ohne mich ausdrücklich gegen alle Eventualitäten abzusichern.
                            Der CLI Mode ist für dich also ein non-standard runmode ?
                            [URL="https://gitter.im/php-de/chat?utm_source=share-link&utm_medium=link&utm_campaign=share-link"]PHP.de Gitter.im Chat[/URL] - [URL="https://raindrop.io/user/32178"]Meine öffentlichen Bookmarks[/URL] ← Ich habe dir geholfen ? [B][URL="https://www.amazon.de/gp/wishlist/348FHGUZWTNL0"]Beschenk mich[/URL][/B].

                            Kommentar


                            • #15
                              Zitat von mermshaus Beitrag anzeigen
                              Beim nächsten Request müssen die Listener dann erst wieder neu registriert werden. Listener registrieren, eine Runde Benachrichtigungen, Listener registrieren, eine Runde Benachrichtigungen, …
                              Das ist ja nicht so schön.

                              Kann man nicht die aktive Session als einen kontinuierlichen Programmlauf betrachten?

                              Das Listener/Dispatcher-Object hält die zu einem Ereignis (USER_CREATE, RESPONSE_BEFORE_SEND,..) eingetragenen Methoden der 'Listener' in der Session.

                              Wenn man ein Ereignis entsprechend qualifiziert, können sich Listener auch z.B. mit 'where'- oder 'on'-Bedingungen eintragen.

                              Reicht das nicht?

                              Kommentar

                              Lädt...
                              X