EventHandler and Delegate in PHP

<?php
/**
 * Implements event handling: attaching Delegates to events and triggering them
 *
 * @author            Ezku (dmnEe0@gmail.com)
 * @since              Jul 12, 2005
 */

class EventHandler
{
        /**
         * @var array   2-dimensional IDelegate map
         */

        protected $listeners = array ( );
       
        /**
         * @var mixed    invocation arguments
         */

        protected $arguments = array ( );
       
        /**
         * Attached listeners will be invoked using whatever arguments the
         * EventHandler was constructed with.
         */

        public function __construct ( )
        {
                $this-> arguments = func_get_args ( );
        }
       
        /**
         * Attach a Delegate to an event
         * @param       string event
         * @param       object IDelegate
         */

        public function attach ( $event, IDelegate $delegate )
        {
                $this-> listeners [ $event ] [ ] = $delegate;
        }
       
        /**
         * Trigger event, invoking all attached listeners
         * @param       string event
         * @return      int      number of listeners invoked
         */

        public function trigger ( $event )
        {
                if ( isset ( $this-> listeners [ $event ] ) && is_array ( $this-> listeners [ $event ] ) )
                {
                        foreach ( $this-> listeners [ $event ] as $delegate )
                        {
                                $delegate-> invoke ( $this-> arguments );
                        }
                        return count ( $this-> listeners [ $event ] );
                }
                return 0;
        }
       
       
        public function __set ( $event, $delegate )
        {
                $this-> attach ( $event, $delegate );
        }
       
        public function __call ( $event, $args )
        {
                $this-> trigger ( $event );
        }
}

interface IDelegate
{
        /**
         * Invoke subordinate
         * @param       array  arguments, optional
         * @return      mixed subordinate return value
         */

        public function invoke ( $args = NULL );
}

/**
 * Calls a method on an object upon invocation
 *
 * @author            Ezku (dmnEe0@gmail.com)
 * @since              Jul 12, 2005
 */

class Delegate implements IDelegate
{
        protected $subordinate = NULL;
        protected $method = NULL;
       
        public function __construct ( $subordinate, $method )
        {
                $this-> subordinate = $subordinate;
                $this-> method = $method;
        }
       
        public function invoke ( $args = NULL )
        {
                Handle:: resolve ( $this-> subordinate );
                return call_user_func_array ( array ( $this-> subordinate, $this-> method ), ( array ) $args );
        }
}

/**
 * Calls a static method on a class upon invocation
 *
 * @author            Ezku (dmnEe0@gmail.com)
 * @since              Jul 14, 2005
 */

class StaticDelegate implements IDelegate
{
        protected $class = NULL;
        protected $method = NULL;
        protected $file = NULL;
       
        /**
         * @param       string class name
         * @param       string method name
         * @param       string file to be included before invocation, optional
         */

        public function __construct ( $class, $method, $file = NULL )
        {
                $this-> class = $class;
                $this-> method = $method;
                $this-> file = $file;
        }
       
        public function invoke ( $args = NULL )
        {
                if (! empty ( $this-> file ) )
                {
                        require_once ( $this-> file );
                }
                return call_user_func_array ( array ( $this-> class, $this-> method ), ( array ) $args );
        }
}

/**
 * "A Handle represents an uninstantiated object that takes the place of a
 * given object and can be swapped out for the object.
 * Implements lazy loading for composing object heirarchies."
 *
 * @author            Ezku (dmnEe0@gmail.com)
 * @since              Jul 12, 2005
 * @see   http://wact.sourceforge.net/index.php/ResolveHandle
 */

class Handle
{
        /**
         * @var string   class name
         */

        protected $class = NULL;
        /**
         * @var array    class constructor arguments
         */

        protected $args = array ( );
        /**
         * @var string   class definition file
         */

        protected $file = NULL;
       
        /**
         * @param       string class name
         * @param       array  class constructor arguments
         * @param       string class definition filename, optional
         */

        public function __construct ( $class, $args, $file = NULL )
        {
                $this-> class    = (string )  $class;
                $this-> args          = ( array )    $args;
                $this-> file          = (string )    $file;
        }
       
        /**
         * Resolves a Handle; replaces a Handle instance with its identified class
         * @param       object passed by reference
         */

        static public function resolve (& $handle )
        {
                if ( $handle instanceof self )
                {
                        $class = $handle-> getClass ( );
                        $file = $handle-> getFile ( );
                       
                        if (! class_exists ( $class ) && ! empty ( $file ) && is_readable ( $file ) )
                        {
                                require_once ( $file );
                        }
                        /**
                         * newInstance seems to be misdocumented: it's actually newInstance ( [mixed args [, ...]] ).
                         */

                        $handle = call_user_func_array ( array ( new ReflectionClass ( $class ), 'newInstance' ), $handle-> getArgs ( ) );
                }
        }
       
        public function getClass ( ) { return $this-> class; }
        public function getFile ( ) { return $this-> file; }
        public function getArgs ( ) { return $this-> args; }
}






/**
 * Example follows
 */







/**
 * A class that composes an EventHandler for attaching Observers
 */

class Observable
{
        /**
         * @var object   EventHandler
         */

        public $events = NULL;
       
        public function __construct ( )
        {
                $this-> events = new EventHandler ( $this );
        }
       
        public function foo ( )
        {
                echo "Observable: method foo called /n<br />";
                $this-> events-> onFoo ( ); // Triggers the event "onFoo"
        }
       
        public function bar ( )
        {
                echo "Observable: method bar called /n<br />";
                $this-> events-> onBar ( ); // Triggers the event "onBar"
        }
}

/**
 * A matching Observer class for Observable
 */

class Observer
{
        public function __construct (Observable $observable )
        {
                /**
                 * Setting a delegate to a property of an EventHandler is the same
                 * as calling attach() - a nice short cut. Note that you aren't limited
                 * to one listener per event, there can be several.
                 */

                $observable-> events-> onFoo = new Delegate ( $this, 'callback_foo' );
                $observable-> events-> onBar = new Delegate ( $this, 'callback_bar' );
        }
        public function callback_foo (Observable $observable )
        {
                echo "Observer: event onFoo triggered /n<br />";
        }
       
        public function callback_bar (Observable $observable )
        {
                echo "Observer: event onBar triggered /n<br />";
        }
}

/**
 * Let's demonstrate a bit
 */


$observable = new Observable;
$observer       = new Observer ( $observable );

$observable-> foo ( );
$observable-> bar ( );

/**
 * Now, imagine you want an object to respond to an event, but you don't want
 * to include it's definition or instantiate it before you really have to. This
 * is lazy loading, just what Handle is for.
 *
 * Let's imagine there's a class named ColossalObserver that resides in
 * ColossalObserver.php and has a method named `callback` - let's create a
 * Handle and attach it.
 */


$colossal = new Handle ( 'ColossalObserver', NULL, 'ColossalObserver.php' );
$observable-> events-> onBar = new Delegate ( $colossal, 'callback' );

/**
 * The rest is left as an exercise for the reader.
 */

?>
 
  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值