4

I would like to implement an Event system in my custom MVC framework, to allow decoupling of classes that need to interact with each other. Basically, the ability for any class to trigger an event and any other class that listens for this event to be able to hook into it.

However, I cannot seem to find a correct implementation given the nature of php's share nothing architecture.

For instance, let's say that I have a User model that each time that it is updated, it triggers a userUpdate event. Now, this event is useful for class A (for instance) as it needs to apply its own logic when a user is updated. However, class A is not loaded when a user is updated, so it cannot bind to any events triggered by the User object.

How can you get around such a scenario? Am I approaching it wrongly?

Any ideas would be greatly appreciated

5
  • Hmmm, wouldn't it be better to handle your event bindings in the controller? Commented Dec 1, 2013 at 20:05
  • Why can't you load class A ahead of time? Somewhere there should be logic that realizes the user model is going to be used, and so other components need to be wired up to it. I'm also not sure why you mentioned shared nothing architecture Commented Dec 1, 2013 at 20:06
  • 1
    Have you consulted the observer/observable design pattern? sitepoint.com/understanding-the-observer-pattern Commented Dec 1, 2013 at 20:30
  • Hi, thanks for the link, I will have a look Commented Dec 1, 2013 at 20:59
  • If you like to implement the observer pattern have a look at SplObserver interface and SplSubject interface Commented Dec 1, 2013 at 21:14

1 Answer 1

6

There must be an instance of class A before the event is triggered because you must register for that event. An exception would be if you'd register a static method.

Let's say you have an User class which should trigger an event. First you need an (abstract) event dispatcher class. This kind of event system works like ActionScript3:

abstract class Dispatcher
{
    protected $_listeners = array();

    public function addEventListener($type, callable $listener)
    {
        // fill $_listeners array
        $this->_listeners[$type][] = $listener;
    }

    public function dispatchEvent(Event $event)
    {
        // call all listeners and send the event to the callable's
        if ($this->hasEventListener($event->getType())) {
            $listeners = $this->_listeners[$event->getType()];
            foreach ($listeners as $callable) {
                call_user_func($callable, $event);
            }
        }
    }

    public function hasEventListener($type)
    {
        return (isset($this->_listeners[$type]));
    }
}

Your User class can now extend that Dispatcher:

class User extends Dispatcher
{
    function update()
    {
        // do your update logic

        // trigger the event
        $this->dispatchEvent(new Event('User_update'));
    }
}

And how to register for that event? Say you have class A with method update.

// non static method
$classA = new A();
$user = new User();
$user->addEventListener('User_update', array($classA, 'update'));

// the method update is static
$user = new User();
$user->addEventListener('User_update', array('A', 'update'));

If you have proper autoloading the static method can be called. In both cases the Event will be send as parameter to the update method. If you like you can have an abstract Event class, too.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.