An event in object-oriented programming (OOP) is a message that occurs at various points in the executable code when certain conditions are met. These messages are sent to processors (listeners), which allows you to react in a timely manner to the changed state of the system.
Event-oriented programming is very popular. This programming paradigm says that program execution is determined by events — user actions (keyboard, mouse), messages from other programs and threads, operating system events, etc.
The advantages and scope of the event model are extremely wide:
- when associating objects with events, objects do not need to “know” about each other;
- this mechanism fits neatly into the concept of OOP;
- This mechanism makes it easy to implement user interfaces, where every user action is an event, it is enough to “hang” on these events handlers;
- when implementing server applications, the event model allows one to get rid of the generation of a multitude of serving processes;
- The event model is also often used when programming games in which a variety of objects are managed.
There are design patterns that are somehow related to event handling: Observer, Team, Chain of Responsibilities, and many others. These templates are used in many event handling models. However, various implementations of the event model impose a number of restrictions on the possibilities of developing programs:
- when processing the event, it is impossible to select the main handler, all handlers are equal to each other;
- when processing the event, handlers do not know anything about each other and about the current situation, which does not allow the programmer to fully realize the intended functionality;
- it is necessary to add additional functionality if you need to select the resulting handler.
The list of listed restrictions is not complete, but these restrictions are the most significant. This article proposes the implementation of a more complex event model, which will remove all of these restrictions.
When developing software using this event-handling model, the sequence of processing steps is as follows:
- Necessary listeners are connected to handle their events.
- In the program code, an event is triggered.
- The “first round” of processing is performed, all listeners who are connected to the processing of this event are given the time for initial processing, during which each listener can get their own data, data from the event initiator, and also set any data to be transmitted to the “second circle” and apply for handling the event in the "second round".
- Among all the listeners of this event, the listener who submitted the application with the highest processing priority is selected; he is given the right to handle the event in the “second round”. In the course of this processing, it can receive data from the initiator, its own data, data from its own “first round” handler. After processing is complete, it can return the data directly to the event initiator.
Consider the advantages of this model:
- It is possible to “hang” the same handler on different events or even on the same thing, but with different own data.
- It is possible to handle the widest range of events. For example, adding a new user, displaying a site page design, etc. In this case, the event of adding a new user can be processed using only the “first circle”, and the output event of the site page design should be processed into “two circles”.
- Only one handler of the “second circle” is executed (Consider the site design output event: on the first circle, the processors push the priorities of the event processing and, on the second circle, one of them generates the design of the site page).

The picture shows the implementation scheme of this model. This implementation is initially based on work using a call chain. Below is an example of implementing the model in PHP.
- Events is the main class. Only its user object can create itself. This class provides the ability to trigger events and "hang" event handlers.
- newListener - allows you to add a new listener and immediately “configure” it (adding occurs via the adapter for Events_Listener - Events_Listener_adapterSET).
- newEvent - allows you to configure a new event, and then initiate it (this action takes place through an adapter for Events_Fire - Events_Fire_adapterSET).
Other classes are also transparently connected to the work process:
- Events_Fire - provides a general interface for working with an event that adapters limit;
- Events_Fire1 - when calling the first round of processing. This class allows you to get all the available data of the current state, add a second-round handler, and also set its priority (via the Events_Fire2_adapterSET adapter);
- Events_Fire2 - when calling the result handler (“second round”). This class allows you to get all the available data, including data from the "first round" processor;
- Events_Listener - provides a general interface for working with an event handler. Methods of this class also use adapters Events_Fire1, Events_Fire2;
- Events_Data - class for storing and transferring data within the event model.
Consider an example of the work of this model:
class SampleListener { public function Fire1(Event_fire1 $EF1) { $EF1->setFinal(Array($this,”Fire2”), $EF1->getListenerData()->sort); } public function Fire2(Event_fire2 $EF2) { return ($EF2->getListenerData()->sort() + $EF2->getFireData()->sort()); } } $listener = new SampleListener(); $data1 = new Events_Data(); $data1->sort = 10; Events::newListener("sampleModul", "sampleEvent", Array($listener, 'Fire1'))->setData($data1); $data2 = new Events_Data(); $data2->sort = 20; Events::newListener("sampleModul", "sampleEvent", Array($listener, 'Fire1'))->setData($data2); $data3 = new Events_Data(); $data3->sort = 30; Echo Events::newEvent("sampleModul", "sampleEvent")->setData($data3)->fire();
After the
sampleEvent event is
initialized, the Fire1 method of the listener $ listener with the first data
(sort = 10, this is the priority that it will put to final processing) is called, and then the same method is called with other data
(sort = 20, 20> 10, therefore the listener with these data and get the right to final processing of the event) . Finally, the Fire2 method will be
called (the handler is the same, but the data is $ data2) . The data from the event
(sort = 30) is added to the data from the listener
(sort = 20) . As a result, the event in response will return us the number 50, which will be displayed on the screen.
This example shows that the same handler can respond differently to an event depending on the data of the listener. It also demonstrates the processing of the event, including the resultant, only call to
Fire2 (Imagine that it is in this method, for example, that the design of the site page is generated, and the data is the external context of the event handling) .
')
By implementing this event-handling model, we managed to remove all the above limitations. Currently, the model is focused on a specific product (there are parasitic methods necessary only in this product), but if there is interest, then you can prepare the code for the public version.
You can also implement this model in other programming languages. In cpp, you can pass a pointer as data, and in processing methods you can use reinterpret_cast or use templates.
The implementation in each specific situation may differ slightly, but the main point is precisely in the implementation of two or more levels.