Decorating event dispatchers

Hi,

I stumbled upon a problem and I wanted to hear what others think about it.

I have the following code:

class A {
    public function doSomething() {
        $externalEventsSource = $this->getExternalEventsSource();
        $externalEventsSource->addEventListener( 
            'EVENT', 
            array( 'callback' => array( $this, 'onEvent' ) ) 
        );
    }
    public function getExternalEventsSource() {
        // retrieves an object that dispatches certain (external) events
    }
    public function onEvent( $event ) {
        // do something
    }
}

// extend so that BaseDecorator gains the A type
class BaseDecorator extends A {
    protected $a;
    public function __construct( A $a ) {
        $this->_a = $a;
    }
    public function doSomething() {
        $this->_a->doSomething();
    }
    public function getExternalEventsSource() {
        return $this->_a->getExternalEventsSource();
    }
    public function onEvent( $event ) {
        $this->_a->onEvent( $event );
    }
    public function __call( $method, $args ) {
        // calls to nonexistent methods are routed to the decorated object
        return call_user_func_array( array( $this->_a, $method ), $args );
    }
}

$d = new BaseDecorator( new A() );
$d->doSomething();

Now, the problem is that I want class A to attach to externalEventsSource’s events with the decorator’s onEvent() method to benefit from the enhanced behavior the decorator provides.

The above example is simplified. I do not want to rewrite BaseDecorator::doSomething() method because in the real life situation there’s a lot of code in there which I would end up duplicating for every decorator I add. More, if my decorated class listens to more than one events I may want to attach with only SOME of the decorator’s methods to the externalEventsSource object.

What suggestions do you have?

A solution I’ve considered is adding a setContext( $context ) method to A. This would result in:

class A {
    public function setContext( $context ) {
        $this->_context = $context;
    }
    public function doSomething() {
        $context = ( $this->_context !== null ? $this->_context : $this );
        $externalEventsSource = $this->getExternalEventsSource();
        $externalEventsSource->addEventListener( 
            'EVENT', 
            array( 'callback' => array( $context, 'onEvent' ) ) 
        );
    }
    public function getExternalEventsSource() {
        // retrieves an object that dispatches certain (external) events
    }
    public function onEvent( $event ) {
        // do something
    }
}

// extend so that BaseDecorator gains the A type
class BaseDecorator extends A {
    protected $a;
    public function __construct( A $a ) {
        $a->setContext( $this );
        $this->_a = $a;
    }
    public function setContext( $context ) {
        $this->_a->setContext( $context );
    }
    public function doSomething() {
        $this->_a->doSomething();
    }
    public function getExternalEventsSource() {
        return $this->_a->getExternalEventsSource();
    }
    public function onEvent( $event ) {
        $this->_a->onEvent( $event );
    }
    public function __call( $method, $args ) {
        // calls to nonexistent methods are routed to the decorated object
        return call_user_func_array( array( $this->_a, $method ), $args );
    }
}

What do you think about this solution?

Thanks in advance.

Don’t mention it.

You might be right.

Yes, something like that.

I also develop the wrapees (is that a word?), so yes, I am in control over their code.

Can you please provide a small code example? I don’t quite understand what you mean.

I apologize, it seems that I’m not explaining my issue correctly.

As I’ve said, in my system I have widgets. Widget classes have a standard functionality and that functionality is usually achieved by listening to events from other widgets. If I want to enhance the functionality of an widget (or parts of the functionality) basically I have two options:

  1. I can choose to extend a widget and override some methods to implement the enhancements
  2. I can choose to decorate a widget (create a wrapper class that holds a reference to that widget) and add the enhancements.

It’s the old “is a” versus “has a” or inheritance versus composition thing that I’m sure you know better than me.

For various reasons I chose to use option number 2. So in code:

class Widget {
    protected $_otherWidget;
    public function __construct( $otherWidget ) {
        $this->_otherWidget = $otherWidget;
    }
    public function doSomething() {
        $this->_otherWidget->addEventListener( 
            'EVENT', 
            array( 
                'callback' => array( $this, 'onEvent' ),
                'options' => array( 'autoRemove' => true ) 
            ) 
        );
    }
    public function onEvent( $event ) {
        $this->_doSomething();
    }
    protected function _doSomething() {}
}

Now, the point where I want to add my enhancements is (unfortunately) the Widget::onEvent() method. So, following a “standard” decorator pattern implementation:

class SomeDecorator extends Widget {
    protected $_widget;
    public function __construct( $widget ) {
        $this->_widget = $widget;
    }
    public function doSomething() {
        // this is where the problem is
        // because _widget will subscribe 
        // to _otherWidget's events with
        // its own methods.
        $this->_widget->doSomething();
    }
    public function onEvent( $event ) {
        // enhanced behavior
        $this->_doSomethingInteresting();
        $this->_widget->onEvent( $event );
    }
    protected function _doSomethingInteresting() {}
} 

Eventually I want to be able to do this:

$widget = new Widget( new OtherWidget() );

if ( $something ) {
    $widget = new SomeDecorator( $widget );
} elseif ( $somethingelse ) {
    $widget = new OtherDecorator( $widget );
} else {
    $widget = new SomeDecorator( new OtherDecorator( $widget ) );
}

$widget->doSomething();

which seems very powerful to me, but would be hell implemented using inheritance.

There are a few solutions to this.

First:

class SomeDecorator extends Widget {
    protected $_widget;
    public function __construct( $widget ) {
        $this->_widget = $widget;
    }
    public function doSomething() {
        $this->_widget->_otherWidget->addEventListener(
        'EVENT',
        array(
            'callback' => array( $this, 'onEvent' ),
            'options' => array( 'autoRemove' => true )
        )
    );
    }
}

but this seems to create a weird coupling between the decorator and the widget because now the decorator needs to have a little too much knowledge about the widget’s internals (what methods are used as callbacks) and can be messy when the widget listens to many events on many other widgets.

Second:

class SomeDecorator extends Widget {
    protected $_widget;
    public function __construct( $widget ) {
        $this->_widget = $widget;
    }
    public function doSomething() {
        $this->_widget->_otherWidget->addEventListener(
            'EVENT',
            array(
                'callback' => array( $this, 'onEvent' ),
                'options' => array( 'autoRemove' => true )
            )
        );
        $this->_widget->doSomething();
    }
    public function onEvent( $event ) {
        $this->_doSomethingInteresting();
    }
}

here the decorator attaches itself to _otherWidget’s events using the method providing the enhancements BEFORE the decorated widget. I think this may cause trouble when wrapping a widget in multiple decorators and may involve prioritizing event listeners (which my system supports).

The third solution is the one from my first post (giving the widget a reference to the top of the decorators stack).

Since each of these solutions have an ugly side I’m wondering if I’m not “forcing” the decorator pattern on this issue. So, my issue is more related to the implementation of the decorator pattern than it is about the implementation of the observer pattern.

How would you solve this?

Thanks in advance.

Something like:


class A {
  public function getExternalEventsSource() {
    // retrieves an object that dispatches certain (external) events
  }
  public function onEvent( $event ) {
    // do something
  }
}

// extend so that BaseDecorator gains the A type
class BaseDecorator extends A {
  protected $a;
  public function __construct( A $a ) {
    $this->_a = $a;
  }
  public function doSomething() {
    $this->_a->doSomething();
  }
  public function getExternalEventsSource() {
    return $this->_a->getExternalEventsSource();
  }
  public function onEvent( $event ) {
    $this->_a->onEvent( $event );
  }
  public function __call( $method, $args ) {
    // calls to nonexistent methods are routed to the decorated object
    return call_user_func_array( array( $this->_a, $method ), $args );
  }
}

class Registrator {
  public function initialize(A $a) {
    $externalEventsSource = $a->getExternalEventsSource();
    $externalEventsSource->addEventListener( 
      'EVENT', 
      array( 'callback' => array( $a, 'onEvent' ) ) 
    );
  }
}

$d = new BaseDecorator( new A() );
$r = new Registrator();
$r->initialize($d);

Hi,

The post title is not accurate. In fact I want to discuss adding behavior at runtime to event listeners (callbacks).

I’m sure many of you know what event driven programming is. My implementation is very simple. In my system I have Widget objects. Each widget has an event dispatcher instance. The event dispatcher manages a map of event listener objects (the objects are mapped to plain strings which represent event types like FINISHED, ERROR etc). Event listeners hold a callback (usually in the form array( $instance, ‘method’ )) and can be executed. When an event listener is executed its internal callback is called and passed an event object.

It’s a pretty standard observer pattern implementation.

To continue my explanation, widget objects usually perform their job by listening to event dispatched by other widgets. So widgets are both observers and observables.

Now, my problem is with adding behavior (decorating) to methods used as callbacks (see the code from my previous post). Inheritance doesn’t help very much (at least not in the way I want) and decorator pattern seemed like a good fit. But I am afraid not to “force” the pattern on this problem. I am saying this, because the solution from my previous post involves setting a reference to the top decorator (because there can be many decorators wrapping a widget) in the decorated object. As far as I know an object is not suppose to “know” it is being decorated and giving it a reference to the top decorator seems to break that rule.

This is side of the issue I want to discuss.

Thanks in advance.

That’s an interesting problem and I don’t have an immediate answer for you. It does occur to me that it is quite similar to having a private method declared in a super class and the need to access it in a derived class. Only this is happening in run time.

Basically, the code is internal implementation of the wrapee and so can’t be hooked into by the wrapper. Are you in control of the wrapee code? Could you externalise the dependency and delegate it to a third object, which did the registration?

I see what you mean. To be honest at first sight I don’t think this will help. But I’ll play around with the idea and see how it works out. Thanks.

Ah I see, sorry for the confusion.

This is well beyond my experience in this topic. I’ve never used the decorator pattern for anything anywhere near this complex but going back to your initial post, you said:

I do not want to rewrite BaseDecorator::doSomething() method because in the real life situation there’s a lot of code in there which I would end up duplicating for every decorator I add

This sounds odd. If your decorators are inheriting from the base decorator why would you need to repeat the code? It may be a simple case of refactoring the code into smaller methods which can be overridden easily if required.

I think I understand what you’re trying to achieve. Remove the need for object you’re observing to know it’s being observed (removing the dependency on the observer).

I attempted something similar here: http://www.sitepoint.com/forums/showpost.php?p=4529975&postcount=10

That was purely proof of concept and messy.

I played around doing it with closures instead:


<?php 
class EventListener { 
    const READ_PROPERTY = '__get'; 
    const WRITE_PROPERTY = '__set'; 
     
    const BEFORE = 1; 
    const AFTER = 2; 
     
    public $eventHandlers = array(); 
     
    public function listenTo($eventHandler, $object) { 
        $hash = spl_object_hash($object); 
        
        foreach ($object as $key => $value) {
        	$listener = $this;
        	if (is_callable($value)) {
        		$object->$key = function() use ($key, $value, &$listener, $object) {  
        			$listener->triggerEvent($object, EventListener::BEFORE, $key, func_get_args());
        			call_user_func_array($value, func_get_args());
        			$listener->triggerEvent($object, EventListener::AFTER, $key, func_get_args());
        		};
        	}
        }
        
        if (!isset($this->eventHandlers[$hash])) $this->eventHandlers[$hash] = array(); 
        $this->eventHandlers[$hash][] = $eventHandler;         
    } 
     
    public function triggerEvent($object, $when, $event, $args) { 
        $hash = spl_object_hash($object); 
        foreach ($this->eventHandlers[$hash] as $eventHandler) { 
            if ($eventHandler->handleEvent($event, $when, $args) === false){ 
                break; 
                return false; 
            } 
        } 
    }     
}

interface EventHandler { 
    public function handleEvent($event, $when, $args);     
} 

class Foo {
	public $testFunction;
	
	public function __call($func, $args) {
		$function = $this->$func;
		return call_user_func_array($function, $args);
	}
	
	public function __construct() {
		
		$this->testFunction = function() {
			echo 'TestFunction called <br />';
		};
	} 
}

class FooEventHandler implements EventHandler { 
    public function handleEvent($event, $when, $args) { 
        switch ($when) { 
            case EventListener::BEFORE: $whenText = 'before'; break; 
            case EventListener::AFTER: $whenText = 'after'; break; 
        } 
        echo 'event trigered: ' . $whenText . ' ' . $event . ' with args: '; 
        var_dump($args); 
        echo '<br />'; 
    } 
} 


$listener = new EventListener;
$foo = new Foo;
$handler = new FooEventHandler;

$listener->listenTo($handler, $foo);

$foo->testFunction('a', 'b');



?>

It works, but look how the Foo class must be set up.

It would be possible to create the class that uses closures from an existing class definition using reflection, but the object you’re listening to would no longer be an instance of “Foo” it would be “FooWrapper” or similar but would remove the need for a listenable class to be wholly defined using closures.

I decided my initial idea was best.

I gave up on the idea though as it’s not very pretty.