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 è
è ora possibile farlo in phpcodice:var test=function(aValue){ return aValue*10; } alert( test(10) ) // stampa 1000
ed è proprio su questo principio che ho sviluppato un gestore di eventi molto semplice ma efficace.Codice PHP:
$test=function($val){
echo $val*10;
}
$test(10) // stampa 100
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);
?>