📜 ⬆️ ⬇️

Observer pattern implementation using PHP 5.3

Having recently read the PHP 5.3 innovations, I drew attention to several interesting features, putting together which you can get an implementation of the Observer design pattern, much more beautiful than those available in pear and symfony, and the entire implementation will take only a few lines of code.

New in PHP5.3
Anonymous functions.
Anonymous functions allow us to create callbacks, actually in place, without declaring any functions in the underlying code.

__invoke ()
Thanks to the new magic method, we can redefine the event that occurs when the object is called. That is, in fact, an object can be accessed as a function.

Event class
Let's start with the Event class itself. Reading other people's sources could not go empty and the only way to manage events, which I saw at the beginning, was to implement heaps of connectEvent methods, etc.
Because of my natural laziness, I didn’t want to do this routine once again, and then I remembered the wonderful ArrayObject class, which allows storing data directly in an object and working with them directly as with array elements. Here's what happened:
')
<?php class Event extends ArrayObject { public function __invoke() { foreach($this as $callback) call_user_func_array($callback, func_get_args()); } } 


An object of this class will hold callbacks in itself, and when accessing an object as a function, it will call all callbacks in turn.
Example:

 <?php $test = new Event(); /* Setting up callbacks */ $test[] = function($msg, $txt) { echo "This is the event! <br />"; }; $test[] = function($msg, $txt) { echo "<b>Message</b>: $msg. <b>Text</b>: $txt <br />"; }; $test[] = function($msg, $txt) { echo "Works great! <br />"; }; /* call */ $test("Some message", "Some text"); 


Now, it would seem, only a little remains - to screw it to some class. But everything is not so simple.

Class Eventable
The fact is that when trying to access a property as a function, PHP will try to find such a function in the class and will generate an error, instead of calling __invoke for property.
You can verify this example:

 class Test { public $onA; public function __construct() { $this->onA = new Event(); } public function A($txt) { $this->onA("This is A.", $txt); } } $test = new Test(); $test->onA[] = function($msg, $txt) { echo "This is the event! <br />"; }; $test->A("Le Test"); 


This means that we will have to convince the class that it wants to call a function, especially since there is no such. I am afraid that this will have to use a crutch and I will be very grateful if someone offers a solution more beautiful than this:

 <?php class Eventable { public function __call($name, $args) { if( method_exists($this, $name) ) call_user_func_array(array(&$this, $name), $args); else if( isset($this->{$name}) && is_callable($this->{$name}) ) call_user_func_array($this->{$name}, $args); } } 


Now it only remains to expand the Test from Eventable and enjoy the result:

 class Test extends Eventable { public $onA; public function __construct() { $this->onA = new Event(); } public function A($txt) { $this->onA("This is A.", $txt); } } $test = new Test(); /* setting up callbacks */ $test->onA[] = function($msg, $txt) { echo "This is the event! <br />"; }; $test->onA[] = function($msg, $txt) { echo "<b>Message</b>: $msg. <b>Text</b>: $txt <br />"; }; $test->onA[] = function($msg, $txt) { echo "Works great! <br />"; }; /* call */ $test->A("Le Test"); 


By the way, as callbacks you can specify not only anonymous functions, but also normally declared and even class methods!

 $test->onA[] = "some_function"; $test->onA[] = array(&$some_object, "some_method"); 

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


All Articles