📜 ⬆️ ⬇️

Symfony Components, Event Dispatcher (theory, part 1)

image
Hey. This translation is conceived as the first (there will be two in total) part of the documentation for the Event Dispatcher component. This component belongs to the Symfony component family , but at the same time it is independent and can be used without connecting the framework, which makes it even more valuable. Translation can still be interpreted as a review 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 being actively processed for compatibility with the PHP version> = 5.3, and it is planned to use the new version of the Symfony 2 framework. The code for the new version of the component can be found here . The names and essence of the methods in the new edition are almost not changed, so the material will be useful and studying the component code for PHP 5.3. So, let's begin.

Event Dispatcher Component - what is it?

Symfony Event Dispatcher is a PHP library, which is a lightweight implementation of an Observer design pattern. This is a good way to make your code more flexible. This is also a good way to make the code suitable for expansion by third-party developers (plugin 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 the Event Dispatcher component in symfony is to be as fast as possible. There is no need to declare interfaces or extend complex classes, events are simple strings, and the notification code is very lightweight. Add any number of handlers and calls without additional problems.
')
Introduction

An object-oriented approach has come a long way so that the code of your projects is 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 have made their subclasses to change behavior, the inheritance code becomes ambiguous.

As an example of life, you may want to provide a plugin system for your class. A plug-in should have the ability to add methods, or do something before or after the work of the method, without interacting with other plug-ins. This problem is not easy to solve by single inheritance, and multiple inheritance (if it were possible in PHP) has its drawbacks.

The main purpose 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 dispatch events to the dispatcher. Once the event has been dispatched, the dispatcher will trigger the appropriate handlers.

Developments

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

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 unwarranted level of complexity.

The event is uniquely identified by a string. By convention, it is best to use lowercase letters, numbers, and underscores (_) for event names. In addition, to better organize your events, a good agreement would be to prefix 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 names of the events 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 class sfEvent, stores information about the event being announced. Its constructor takes three arguments:Most often the event is called in the context of the 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 information about an event:
The event object can also be used as an array to receive parameters:
echo $ event [ 'culture' ];

Add handlers

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

The connect () method takes two arguments:
Note: PHP callable is a PHP variable that can be used by the call_user_func () function and returns true when passed to the is_callable () function. The string represents a function, and the 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 dispatcher, it waits for a call to the corresponding event. The event manager keeps a record of all event handlers, and knows which one to trigger when an event occurs.

Note: event handlers are invoked by the event dispatcher in the order you attached them.

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

Event announcement

An event can be declared by one of three methods:
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 let the handler 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 handlers until one of them returns true, and after that it will stop 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 triggers an event can verify that the event handler handled the event by calling the isProcessed () method:
if ($ event ->isProcessed())
{
$ret = $ event ->getReturnValue();

// ...
}


filter ()

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

All handlers receive a value and they must return the filtered value, which they changed or not. All handlers are guaranteed to be called.

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

Source: https://habr.com/ru/post/51505/


All Articles