📜 ⬆️ ⬇️

Signals and slots in PHP. Same as in Qt. Almost

Signals and slots is an approach used in some programming languages ​​and libraries (for example, Boost and Qt) which allows for the implementation of the “observer” pattern, minimizing the writing of repetitive code. The concept is that a component (often a widget) can send signals containing information about an event (for example: the text “word” was highlighted, the second tab was opened). In turn, other components can receive these signals through special functions - slots. A signal and slot system is well suited for describing a graphical user interface. Also, the signal / slot mechanism can be applied to asynchronous I / O (including sockets, pipe, devices with a serial interface, etc.) or event notifications. In the Qt library, thanks to the Meta-Object Compiler (English) Russian. there is no need to write a registration / deregistration / call code, since these sample code sections are generated automatically.
Wikipedia tells us.

There is no event loop in php applications. Received a request, answered. And that's it. However, between “received a request” and “answered” there is some kind of application life cycle, respectively, all is not lost and you can try to apply this mechanism in web applications. As a student I was programming in C ++ / Qt and I really liked the implementation of signals and slots then. Great idea. The closest relative is the Observer pattern. The goal is the same, but the implementation is completely different. I got the idea to implement this mechanism for php in the form of a small library.

Signals and Slots


A signal is something that can inform an external World about the internal state of an object. The phone can call, the cat can "meow." Calls and "meow" are signals of the telephone and the cat, respectively. They tell us about the change in the internal state of the objects: the phone from the state of rest has switched to the state of “you are ringing”, the cat has moved from the state of “fed cat” to the state of “hungry cat”.
')
You can respond to these signals in some way. For example: pick up the phone or finally feed your cat. Your responses to signals are slots.

In programming, there are exactly the same situations when we need to respond to a change in the state of an object. For this purpose, the signals and slots mechanism is used to ensure communication between objects. In my opinion, unlike the “Observer” template, it is simpler and much more transparent in use (although the “Observer” itself is also a very simple template).

A little thought, I wrote a connector library for php, which implements the mechanism of signals and slots. Look at her?

Installation


Connector is available as a composer package, respectively, for installation, you must perform
composer require fluffy/connector 

or add a dependency to the library in your composer.json file
 "require": { ... "fluffy/connector": "^1.0" } 

and execute
 composer update 


Using


1. Signals

If we want the object to emit signals, then we need to implement the SignalInterface interface and use the corresponding SignalTrait SignalTrait . For example, we have a logger class and we want it to send a signal somethingIsLogged whenever it finishes logging:
 <?php /** * @file * Contains definition of Logger class. */ use Fluffy\Connector\Signal\SignalInterface; use Fluffy\Connector\Signal\SignalTrait; /** * Class Logger. */ class Logger implements SignalInterface { use SignalTrait; public function log() { // Do logging stuff. ... // Emit signal about successfull logging. $this->emit('somethingIsLogged', 'Some useful data'); } } 

In order to send a signal, you must call the emit method and pass two parameters: the name of the signal and the data that will be transmitted by this signal. You can transfer any type of data: string, number, array, or object. It's all. Now the object logger is able to send signals to the outside world. But as long as no one is connected to this signal, no one will know that this object reports something useful. Let's fix it.

2. Slots

A slot is an ordinary class method. Let's create a class with a slot.
 <?php /** * @file * Contains definition of Receiver class. */ /** * Class Receiver. */ class Receiver { public function slotReactOnSignal($dataFromSignal) { echo "Received data: $dataFromSignal"; } } 


3. Signal Slot Connections

So, we have a Logger class with a signal and a Receiver class with a slot. In order to respond to a signal, you need to connect a slot to it.
 use Fluffy\Connector\ConnectionManager; $logger = new Logger(); $receiver = new Receiver(); ConnectionManager::connect($logger, 'somethingIsLogged', $receiver, 'slotReactOnSignal'); $logger->log(); 

By calling ConnectionManager::connect($sender, $signalName, $receiver, $slotName) we thereby connected the signal of the logger object to the slot of the receiver object. This means that every time $logger->log() is called, a $logger->log() signal somethingIsLogged will be sent, to which the slotReactOnSignal slot of the slotReactOnSignal object will respond. We can define as many signal slot connections as we need. All possible types of connections work:

Moreover, it does not matter whether they are signals from one object or from different objects, whether they are slots of a single object or different ones.

4. Types of compounds

By default, the ConnectionManager::connect() method creates a permanent connection. This means that the connection will not be broken after the first signal is sent. However, it is possible to create a one-time connection by passing a constant to the fifth parameter — the type of connection. For example:
 use Fluffy\Connector\ConnectionManager; $logger = new Logger(); $receiver = new Receiver(); ConnectionManager::connect($logger, 'somethingIsLogged', $receiver, 'slotReactOnSignal', ConnectionManager::CONNECTION_ONE_TIME); $logger->log(); // Log once again. $logger->log(); 

After the second call to Logger::log() nothing will happen as the slot will be disconnected from the signal after its first expulsion.

5. Disconnect

If we don’t want to listen to a certain signal anymore, then we simply disconnect from it.
 ConnectionManager::disconnect($logger, 'somethingIsLogged', $receiver, 'slotReactOnSignal'); 

If we need to reset all existing connections, then we need to call
 ConnectionManager::resetAllConnections() 


What is it for?



Project repository: fluffy / connector

I hope it was interesting to get to this line. Criticism and thoughts in hearing are welcome.

UPD


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


All Articles