Symfony Components, Event Dispatcher (Theory, Part 1)

Original author: Fabien Potencier, Sensio Labs
  • Transfer
image
Hey. This translation is conceived as the first (there will be two) part of the documentation for the Event Dispatcher component . This component is part of the Symfony family of components , but at the same time it is independent and can be used without connecting the framework, which makes it even more valuable. The translation can still be interpreted as an overview of the lightweight implementation of the Observer pattern in php, which is designed to enhance the interaction between classes.

I want to say that the component family is now actively being processed for compatibility with the version of PHP> = 5.3, and it is planned to use it with the new version of the Symfony 2 framework . The code for the new version of the component can be viewed here.. The names and essence of the methods in the new edition almost did not change, so the material will be useful for code-learning components under PHP 5.3. So, let's begin.

Event Dispatcher Component - what is it?

Symfony Event Dispatcher is a PHP library that is a lightweight implementation of the Observer design pattern. This is a good way to make your code more flexible. It is also a good way to make the code suitable for extension by third-party developers (plug-in development). Third-party code listens for specific events by creating callbacks, and the dispatcher makes calls when your code notifies these events.

Very fast

The main advantage of Symfony's Event Dispatcher is to be as fast as possible. There is no need to declare interfaces or extend complex classes, events are simple strings, and the alert code is very lightweight. Add any number of handlers and calls without additional problems.

Introduction

The object-oriented approach has come a long way in making your projects code extensible. By creating classes with well-defined functionality, you make the code more flexible.

If the user wants to change the behavior of the class, he can extend it using a subclass to override the behavior. But if the user wants to propagate these changes to other users who made their subclasses to change the behavior, the inheritance code becomes ambiguous.

As an example from life, maybe you want to provide a plug-in system for your class. The plugin should be able to add methods, or do something before or at the end of the method, without interacting with other plugins. This problem is not easy to solve by single inheritance, and multiple inheritance (if it were possible in PHP) has its drawbacks.

The main goal of the Symfony Event Dispatcher component is to allow objects to communicate together without knowing each other. This is made possible by the central object, the dispatcher.

Objects (handlers, listeners) can communicate with the dispatcher to listen for specific events, and some others can send events to the dispatcher. As soon as the event is dispatched, the dispatcher will start the corresponding handlers.

Events

Unlike many other Observer implementations, you should not create a class to create a new event. All events, of course, remain objects, but all events are instances of the sfEvent built-in class .

Note: of course, you can extend the sfEvent class to extend the event further, or include some restrictions, but in most cases this will add a new unjustified level of complexity.

An event is uniquely identified by a string. By convention, it is best to use lowercase letters, numbers, and underscores (_) for event names. Also, to better organize your events, a good convention is to prefix the event names with a namespace followed by a period (.).

Here are examples of well-named events:
change_culture
response.filter_content
As you probably noticed, the event names contain a word to indicate what should happen when an event occurs.

Dispatcher

A dispatcher is an object responsible for controlling the register of handlers and calling them when one of the events occurs.
By default, the dispatcher class is sfEventDispatcher :
$dispatcher = new sfEventDispatcher();

Event objects

An event object, of the sfEvent class, stores information about the event being declared. Its constructor takes three arguments:
  • The context (subject) of the event (in most cases this is an object that declares the event, but it can also be null);
  • Event name;
  • Array of parameters for passing them to handlers (by default an empty array).
Most often, an event is fired in the context of an object, the first argument is almost always $ this:
$event = new sfEvent($this, 'user.change_culture', array('culture' => $culture));
An event object has several methods for retrieving event information:
  • getName (): returns the identifier of the event;
  • getSubject (): returns the object of the subject (context), docked to the event;
  • getParameters (): returns an array of event parameters.
An event object can also be used as an array to obtain parameters:
echo $event['culture'];

Adding Handlers

Obviously, you need to attach some handlers to the dispatcher before it can be useful. Calling the dispatcher method connect () associates PHP callable with the event.

The connect () method takes two arguments:
  • Event name;
  • Php callable to call when the event happens.
Note: PHP the callable is a PHP variable that can be used function call_user_func () and returns true when passed to is_callable () function. A string represents a function, and an array can represent an object method or a class method.
$dispatcher->connect('user.change_culture', $callable);
As soon as the handler is registered using the event manager, it waits for the corresponding event to be called. The event manager keeps a record of all event handlers, and knows which one to trigger when the event occurs.

Note: handlers are called by the event manager in the order that you attached them.

For the previous example, $ callable will be called by the dispatcher when the user.change_culture event is declared by the object.
When the handlers are called, the dispatcher passes the sfEvent object to them as a parameter. That is, the handler receives the event object as its first argument.

Event Announcement

An event can be declared in one of three ways:
  • notify ();
  • notifyUntil ();
  • filter ();
notify ()

The notify () method launches all handlers.
$dispatcher->notify($event);

Using the notify () method, you can be sure that all registered handlers of the declared event have been executed, but none of them can return a value to the subject.

notifyUntil ()

In some cases, you need to allow the handler to stop the event and prevent other handlers from learning about the event. In this case, you need to use notifyUntil () instead of notify (). Then the dispatcher will call all the handlers until one of them returns true, and after that it stops the reaction to the event:
$dispatcher->notifyUntil($event);
A handler that stops the chain can also call the setReturnValue () method to return a value to the subject.

Anyone who raised the event can verify that the handler has processed the event by calling the isProcessed () method:
if ($event->isProcessed())
{
 $ret = $event->getReturnValue();

 // ...
}

filter ()

The filter () method requires all handlers to filter the given value passed by the event creator in the second argument and received by the handler as the second argument:
$dispatcher->filter($event, $response->getContent());

All handlers get the value and they must return the filtered value that they changed or not. All handlers are guaranteed to be called.

The one who declared the event can get the filtered value by calling the getReturnValue () method:
$ret = $event->getReturnValue();
In the second part, I plan to translate practical examples of using Event Dispatcher. And then, perhaps, there will be another topic on using the component in a real project.

Also popular now: