Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 13
  1. #1
    Utente di HTML.it L'avatar di dottwatson
    Registrato dal
    Feb 2007
    Messaggi
    3,012

    [PILLOLA] PHP 5.3 - Gestore di eventi

    Buongiorno a tutti.

    Con il rilascio di php 5.3 è stato inserito un nuovo elemento di programmazione già presente in diversi linguaggi, estremamente versatile e dinamico: la gestione delle Closure di cui riporto il link ufficiale della documentazione php qui sotto:

    http://it2.php.net/manual/en/functions.anonymous.php

    quello che quindi in javascript è

    codice:
    var test=function(aValue){
        return aValue*10;
        }
    
    alert( test(10) ) // stampa 1000
    è ora possibile farlo in php

    Codice PHP:
    $test=function($val){
        echo 
    $val*10;
        }

    $test(10// stampa 100 
    ed è proprio su questo principio che ho sviluppato un gestore di eventi molto semplice ma efficace.

    Già in un post di qualche mese fà mi ero chiesto come poter implementare un sistema di eventi in php e sinceramente, anche se avevo ricevuto validi workaround e consigli, mi sono scoraggiato in quanto sicuramente mi mancava uno strumento come appunto le Closures.

    ora che è a disposizione ho rispolverato il progetto ed ecco la classe con tutti i commenti del caso

    Spero possa servire a qualcuno!!

    Codice PHP:
    <?php
    // +------------------------------------------------------------------------+
    // | events.class.php                                                 |
    // +------------------------------------------------------------------------+
    // | Copyright (c) Temperini Mirko 200x. All rights reserved.                  |
    // | Version       0.1                                                     |
    // | Last modified 21/08/2009                                               |
    // | Email         [email]dottwatson@hotmail.it[/email]                                   |
    // | Web           [url]http://www.phpmonster.org[/url]                                |
    // +------------------------------------------------------------------------+
    // | This program is free software; you can redistribute it and/or modify   |
    // | it under the terms of the GNU General Public License version 2 as      |
    // | published by the Free Software Foundation.                             |
    // |                                                                        |
    // | This program is distributed in the hope that it will be useful,        |
    // | but WITHOUT ANY WARRANTY; without even the implied warranty of         |
    // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          |
    // | GNU General Public License for more details.                           |
    // |                                                                        |
    // | You should have received a copy of the GNU General Public License      |
    // | along with this program; if not, write to the                          |
    // |   Free Software Foundation, Inc., 59 Temple Place, Suite 330,          |
    // |   Boston, MA 02111-1307 USA                                            |
    // |                                                                        |
    // | Please give credit on sites that use class.upload and submit changes   |
    // | of the script so other people can use them as well.                    |
    // | This script is free to use, don't abuse.                               |
    // +------------------------------------------------------------------------+
    class events{

        
    /*
        *inizializzo la classe eventi affinchè vada a 
        *conoscere tutti i metodi presenti nel suo utilizzatore
        *e ne raccolgo i nomi per inizializzare i nuovi eventi
        *
        ********************************************************/
        
    public function __construct($related_class){
            
    //  i metodi  magici che non dovranno essere prese in considerazione
            //  dal processo automatico  
            
    $denied=array('__construct','__destruct');
            
    // la lista dei metodi dell' utilizzatore
            
    $methods=get_class_methods($related_class);

            
            foreach(
    $methods as $method){
                
    // se non è nella lista nera
                
    if(!in_array($method,$denied)){
                    
    // supponendo il methodo foo il nome evento sarà onFoo
                    
    $onMethod=$this->set_event_name($method);
                    
    //creo il nuovo evento, ovviamente una funzione vuota
                    
    $this->$onMethod=function(){};
                    }
                }        
            } 

        
    /*
        *access:    public
        *params:    func_name->il nome della funzione a cui sarà agganciato l' evento
        *           $function: la Closure che sarà eseguita         
        */
        
    public function addEvent($func_name,$function){
            
    // supponendo $func_name = foo il nome evento sarà onFoo
            
    $onMethod=$this->set_event_name($func_name);
            
    //associo ad uan variabile della classe elements la Closure appena dichiarata
            
    $this->$onMethod=$function;
            return 
    true;
            }

        
    /*
        *access:    public
        *params:    func_name->il nome della funzione da cui sarà rimosso l' evento         
        */
        
    public function removeEvent($func_name){
            
    // supponendo $func_name = foo il nome evento sarà onFoo
            
    $onMethod=$this->set_event_name($func_name);
            if(isset(
    $this->$onMethod)){
                
    //se esiste, associo all' evento una Closure vuota, come in origine
                
    $this->$onMethod=function(){};
                return 
    true;
                }
            return 
    false;
            }


        
    /*
        *access:    public
        *params:    func_name->il nome della funzione a cui sarà agganciato l' evento
        *           argument 1,argument 2,argument 3 ecc...         
        */

        
    public function fireEvent(){
            
    //gli argomenti passati alla funzione
            
    $__args=func_get_args();
            
            
    //il nome del metodo di riferimento
            
    $methodName=$__args[0];
            
            
    //lo elimino perchè i successivi sareanno passati alla Closure
            
    unset($__args[0]);
            
            
    // supponendo $onMethod = foo il nome evento sarà onFoo
            
    $onMethod=$this->set_event_name($methodName);
            
            
            if(isset(
    $this->$onMethod)){
                
                
    //passaggio fondamentale per utilizzare la Closure!! associo la Closure ad una variabile 
                
    $event=$this->$onMethod;
                
                
    //ci sono argomenti per la mia Closure?
                
    if(!empty($__args)){
                    
    $res=array();
                    foreach(
    $__args as $a_key=>$a_val){
                        
    // un nomedi variabile per passaro alla Closure
                        
    $varName="to_function_".$a_key;
                        
                        $
    $varName=$a_val;
                        
                        
    $res[]='$'.$varName;
                        }
                    
    //lancio l' evento, con sintassi $vent($to_function_2,$to_function_3,$to_function_4...)
                    
    eval('$event('.implode(',',$res).');');
                    }
                else{
                    
    // nonc'erano argomenti, quindi la lancio così com'è!
                    
    $event();    
                    }
                return 
    true;
                }
            return 
    false;
            }
        
        
        private function 
    set_event_name($name=""){
            
    $name=strtolower($name);
            return 
    'on'.ucfirst($name);
            }
        
        }


    class 
    test{
        
        public function 
    __construct(){
            
    //  aggancio alla classe il gestore eventi,il quale accetta come argomento la classe stessa 
            
    $this->events=new events($this);    
            }    
        
        public function 
    launch(){
            echo 
    "i'm the method ".__METHOD__." , ready to go!
    "
    ;
            
            
    // NECESSARIO per lanciare l' evento alla fine della sua esecuzione;
            // ovviamente... PRIMA di un eventuale return!
            
    $this->events->fireEvent(__FUNCTION__);
            }

        public function 
    arrived($now){
            if(
    $now 1000000)
                echo 
    "
    the rocket isn't arrived on the moon :(
    "
    ;
            else
                echo 
    "
    wow! is on the moon!! 
    "
    ;
            }
        }



    /***************************************
    *   TEST TEST TEST TEST TEST TEST TEST
    *   TEST TEST TEST TEST TEST TEST TEST
    *   TEST TEST TEST TEST TEST TEST TEST
    *   TEST TEST TEST TEST TEST TEST TEST
    *   TEST TEST TEST TEST TEST TEST TEST
    *   TEST TEST TEST TEST TEST TEST TEST
    *   TEST TEST TEST TEST TEST TEST TEST
    *   TEST TEST TEST TEST TEST TEST TEST
    ****************************************/


    // inizializzo la classe di test, in cui nel metodo costruttore 'aggancio' la classe che gestisce gli eventi
    $test=new test;


    // un semplice test senza eventi
    $test->launch();
    echo 
    "
    "
    ;


    // creo un evento che assumerà il nome 'onLaunch' nella classe events (quindi $test->events->onLaunch) 
    // 2 paramtri: il metodo target, e la Closure da eseguire
    $test->events->addEvent('launch',
        function(
    $when=0){
            
    $when=($when 0)?$when:time();
            echo 
    "
    the rocket was launched on "
    .date('Y-m-d',$when)." at ".date('H:i:s',$when)." !!
    "
    ;
            }); 

    $test->launch();
    echo 
    "
    "
    ;


    // lancio l'evento in maniera indipendente, senza richiamare launch
    $test->events->fireEvent('launch',time()-86400);
    echo 
    "
    "
    ;

    //rimuovo l'evento
    $test->events->removeEvent('launch');
    $test->launch();
    echo 
    "
    "
    ;


    /*
    * ora una prova su una variabile ESTERNA a tutto, definita chissà dove e chissà come e la modifico
    */
    $VAR=1000000;
    echo 
    "
    the rocket is about 
    {$VAR} kilometers far from the moon!
    "
    ;

    $test->events->addEvent('launch',
        function(
    $kilometers=0) use (&$VAR){
            
    $VAR-=$kilometers;
            echo 
    "
    the rocket is about 
    {$VAR} kilometers far from the moon!!
    "
    ;
            
    $VAR-=rand(100,10000);
            }); 

    $test->events->fireEvent('launch',100);


    $test->events->fireEvent('launch',200);

    echo 
    "
    the rocket is about 
    {$VAR} kilometers far from the moon!
    "
    ;




    $test->events->addEvent('launch',
        function(
    $kilometers=0) use (&$VAR,&$test){
            
    $VAR-=$kilometers;
            echo 
    "
    the rocket is about 
    {$VAR} kilometers far from the moon!!
    "
    ;
            
    $VAR-=rand(100,10000);
            
    $test->arrived($VAR);
            }); 

    $test->events->fireEvent('launch',300);
    ?>
    Non sempre essere l'ultimo è un male... almeno non devi guardarti le spalle

    il mio profilo su PHPClasses e il mio blog laboweb

  2. #2
    Interessante, me lo segnerò per il futuro...

    Thanks

  3. #3
    guest.1
    Guest
    scusa, se mi intrometto , si come vedo che sai già usare il php 5.3 mi dici se i script fatti con php 5.2.9 funzionano ancora con la 5.3?.

    PS: sai perchè sto studiando ora il php dopo le asp net che non mi va più di usarle.

    Comunque bella pillola!
    ora me la vedo ed la studio.

  4. #4
    Originariamente inviato da luigi.amorfini
    scusa, se mi intrometto , si come vedo che sai già usare il php 5.3 mi dici se i script fatti con php 5.2.9 funzionano ancora con la 5.3?.
    Si, certo. Tra una minor release e l'altra non vengono applicati cambiamenti così drastici da indurre addirittura problemi di retrocompatibilità (che vengono comunque evitati anche tra i rilasci delle release maggiori).

  5. #5
    Moderatore di PHP L'avatar di Alhazred
    Registrato dal
    Oct 2003
    Messaggi
    12,503
    Non è proprio vero, se provi ad usare Joomla fino all'attuale 1.5.14 (che è tutto in php) su un server con php 5.3 magicamente non funziona più nulla.

  6. #6
    Originariamente inviato da codesnippet
    Si, certo. Tra una minor release e l'altra non vengono applicati cambiamenti così drastici da indurre addirittura problemi di retrocompatibilità (che vengono comunque evitati anche tra i rilasci delle release maggiori).
    disgraziatamente, anche se questo postulato è quasi sempre valido php rientra tra quei linguaggi che non considerano proprio per nulla

    se è per questo il mio framework aveva smesso di funzionare tra php 5.2.6 e php 5.2.9 a causa di una serie di funzione che ritornavano valori con tipo diverso per indicare il fallimento

    @dottwatson

    l'idea della pillola non è male e le closures rendono infinitamente più semplice l'implementazione di un sistema ad eventi, di assai

    Però, personalmente, preferisco:
    - che sia la classe che necessita degli eventi ad estendere la classe base
    - che la classe che necessità degli eventi non registri gli eventi a priori (anche se questo ti permette di fare maggiori controlli complica il codice, almeno in php)
    - la rimozione degli eventi, almeno per una pagina web, non serve
    - infine sarebbe più appropiato scegliere dei propri nomi per gli eventi

    Riguardo l'ultimo punto, ti faccio un esempio pratico: se ho una proprietà {get|set}Age allora sarebbe appropriato chiamare l'evento changedAge (o ChangedAge, dipende dallo stile di coding utilizzato) ma non farlo richiamare direttamente da setAge bensì da un metodo di intermezzo chiamato ad esempio onChangedAge (o OnChagnedAge)

    Questo semplice sistema permette di ridurre la duplicazione del codice quando si ci ritrova a dover richiamare l'evento da più posti, ad esempio un setPersonalInfo potrebbe acquisire anche l'eta e quindi dover richiamare l'evento changedAge cosa che ti costringerebbe a duplicare il codice.

    Nell'esempio che ho postato, ovviamente, non c'è tutta questa differenza ma negli eventi è comune passare delle variabili con la conseguenza che va ad esempio costruito/inizializzato l'oggetto da passare o l'array ... o i valori necessari insomma e questo vorrebbe dire codice duplicato.

    Infine piuttosto che utilizzare un metodo FireEvents per scatenare gli eventi sarebbe più utile usare il metodo magico __call cosi da semplificare il codice chiamate, però ci sarebbe di fare dei test di performance perché se non ricordo male non era molto performante :\

    detto questo la trovo abbastanza utile

  7. #7
    Ma non capisco,

    la classe che "lancia gli eventi" semplicemente dovrebbe estendere una classe base con la logica event/listener, e quindi richiamare un suo metodo protetto "fire" per lanciare l'evento specificato

    poi devono essere le altre classi che vogliono sapere che cosa succede attaccarsi come listeners..

    Insomma, hai presente come fa il java? l'actionscript? e simili?

    Non capisco il perchè quindi di questa pillola e sarei felice se spiegassi in dettaglio in quali occasioni è utile/efficace/migliore di altre soluzioni

    Grazie
    IP-PBX management: http://www.easypbx.it

    Old account: 2126 messages
    Oldest account: 3559 messages

  8. #8
    Utente di HTML.it
    Registrato dal
    Feb 2008
    Messaggi
    813
    un gestore di eventi lo puoi fare anche (e forse anche meglio) senza closures.
    Vedi Java
    Nell'anno 1968 è bastata la potenza di due Commodore 64 per lanciare con successo una navicella sulla Luna; nell'anno 2007 ci vogliono la potenza di un processore quad core 3.30 GHz e 3 Gb di RAM (requisiti minimi ufficiali) per utilizzare Windows Vista. Qualcosa deve essere andato storto!

  9. #9
    Utente di HTML.it L'avatar di dottwatson
    Registrato dal
    Feb 2007
    Messaggi
    3,012
    Originariamente inviato da daniele_dll
    disgraziatamente, anche se questo postulato è quasi sempre valido php rientra tra quei linguaggi che non considerano proprio per nulla

    se è per questo il mio framework aveva smesso di funzionare tra php 5.2.6 e php 5.2.9 a causa di una serie di funzione che ritornavano valori con tipo diverso per indicare il fallimento

    @dottwatson

    l'idea della pillola non è male e le closures rendono infinitamente più semplice l'implementazione di un sistema ad eventi, di assai

    Però, personalmente, preferisco:
    - che sia la classe che necessita degli eventi ad estendere la classe base
    - che la classe che necessità degli eventi non registri gli eventi a priori (anche se questo ti permette di fare maggiori controlli complica il codice, almeno in php)
    - la rimozione degli eventi, almeno per una pagina web, non serve
    - infine sarebbe più appropiato scegliere dei propri nomi per gli eventi

    Riguardo l'ultimo punto, ti faccio un esempio pratico: se ho una proprietà {get|set}Age allora sarebbe appropriato chiamare l'evento changedAge (o ChangedAge, dipende dallo stile di coding utilizzato) ma non farlo richiamare direttamente da setAge bensì da un metodo di intermezzo chiamato ad esempio onChangedAge (o OnChagnedAge)

    Questo semplice sistema permette di ridurre la duplicazione del codice quando si ci ritrova a dover richiamare l'evento da più posti, ad esempio un setPersonalInfo potrebbe acquisire anche l'eta e quindi dover richiamare l'evento changedAge cosa che ti costringerebbe a duplicare il codice.

    Nell'esempio che ho postato, ovviamente, non c'è tutta questa differenza ma negli eventi è comune passare delle variabili con la conseguenza che va ad esempio costruito/inizializzato l'oggetto da passare o l'array ... o i valori necessari insomma e questo vorrebbe dire codice duplicato.

    Infine piuttosto che utilizzare un metodo FireEvents per scatenare gli eventi sarebbe più utile usare il metodo magico __call cosi da semplificare il codice chiamate, però ci sarebbe di fare dei test di performance perché se non ricordo male non era molto performante :\

    detto questo la trovo abbastanza utile
    rispondo per steps:
    Però, personalmente, preferisco:
    - che sia la classe che necessita degli eventi ad estendere la classe base
    vero sarebbe teoricamente piu logico, ma per renderla meno invasiva ho deciso di fare gestire gli eventi direttamente alla classe events, per quanto possano avere strettissima cooperazione sia la classe events che la classe utilizzatrice, ho preferito che events stesso gestisca gli eventi.

    - la rimozione degli eventi, almeno per una pagina web, non serve
    qual' ora uno si strutturerebbe con l'inizializzazione degli eventi in una fase di 'inizializzazione' potrebbe venire utile... se successivamente a==true l'evento rimane, viceversa removeEvent

    infine sarebbe più appropiato scegliere dei propri nomi per gli eventi
    ver. 0.1, e siceramente stavo già pensando a come poter gestire questa cosa in maniera semplice e non troppo pragmatica. Il mio scopo è di automatizzare il più possibile alcune procedure, scaricando lo sviluppatore dal dovere introdurre codice all' interno dei metodi


    Ad ogni modo sono aperto a qualsiasi suggerimento e consiglio (sia logico che di codice)

    Grazie dan!
    Non sempre essere l'ultimo è un male... almeno non devi guardarti le spalle

    il mio profilo su PHPClasses e il mio blog laboweb

  10. #10
    Utente di HTML.it L'avatar di dottwatson
    Registrato dal
    Feb 2007
    Messaggi
    3,012
    Originariamente inviato da Santino83_02
    Ma non capisco,

    la classe che "lancia gli eventi" semplicemente dovrebbe estendere una classe base con la logica event/listener, e quindi richiamare un suo metodo protetto "fire" per lanciare l'evento specificato

    poi devono essere le altre classi che vogliono sapere che cosa succede attaccarsi come listeners..

    Insomma, hai presente come fa il java? l'actionscript? e simili?

    Non capisco il perchè quindi di questa pillola e sarei felice se spiegassi in dettaglio in quali occasioni è utile/efficace/migliore di altre soluzioni

    Grazie
    rispondo a te ma l'argomento riguarda anche Hysoka:

    il problema fondamentale per me è riuscire ad ottenere un trigger sui medhodi richiamati dall' utente e che esistono realmente nella classe. L' unico trigger a disposizione in questo momento è quello sui metodi INESISTENTI (__call() )


    detto questo replico all' utilità degli eventi:
    quante possibilità ho io di poter 'estendere' un metodo già definito in una classe php?
    io penso per esempio al discorso della gestione di un catalogo dove i prezzi e relativi sconti possono essere definiti in base a mille parametri..

    Codice PHP:
    class prezzo{
        public function 
    __construct(){
            
    $this->events=new events($this);
            }
        
        
        public function 
    set_prezzo($value){
            
    // codice...
            
            
    $this->fireEvent(__FUNCTION__);
            }
        
        
        function 
    sconto_fedelta(){
            
    //codice...
            
    }
        function 
    sconto_rivenditore(){
            
    //codice...
            
    }
        function 
    sconto_primo_acquisto(){
            
    //codice...
            
    }
        }


    $prezzo=new prezzo;



    switch(
    $user_type){
        case 
    1:
           
    $prezzo->events->addEvent('set_prezzo',
                function () use (&
    $prezzo){
                    
    $prezzo->sconto_fedelta();
                    }
           ) 
        break;
        case 
    2:
           
    $prezzo->events->addEvent('set_prezzo',
                function () use (&
    $prezzo){
                    
    $prezzo->sconto_rivenditore();
                    }
        break;
        case 
    3:
           
    $prezzo->events->addEvent('set_prezzo',
                function () use (&
    $prezzo){
                    
    $prezzo->sconto_primo_acquisto();
                    }
        break;
        }

    $prezzo->set_prezzo(1000);

    ?> 
    Non sempre essere l'ultimo è un male... almeno non devi guardarti le spalle

    il mio profilo su PHPClasses e il mio blog laboweb

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.