Реализация Шаблона Observer С Использованием Php 5.3

Прочитав недавно о нововведениях в PHP 5.3, я заметил несколько интересных особенностей, которые в совокупности могут создать реализацию шаблона проектирования Observer, гораздо более красивую, чем те, что доступны в pear и Symfony, а вся реализация займет всего лишь несколько минут. несколько строк кода.

Новое в PHP5.3 Анонимные функции.

Анонимные функции позволяют нам создавать обратные вызовы прямо на месте, без объявления каких-либо функций в основном коде.

__invoke() Благодаря новому магическому методу мы можем переопределить событие, возникающее при вызове объекта.

То есть фактически к объекту можно обращаться как к функции.

Класс события Начнем с самого класса Event. Чтение чужих исходников не могло быть пустой тратой времени, и единственный способ управления событиями, который я видел изначально, — это реализовать кучу методов типа ConnectEvent и т.п.

Из-за моей природной лени мне не хотелось снова сталкиваться с этой рутиной, и тогда я вспомнил о замечательном классе ArrayObject, который позволяет хранить данные непосредственно в объекте и работать с ним напрямую, как с элементами массива.

Вот что произошло:

  
  
  
  
  
   

<Эphp class Event extends ArrayObject { public function __invoke() { foreach($this as $callback) call_user_func_array($callback, func_get_args()); } }

Объект этого класса будет хранить обратные вызовы, и при обращении к объекту как функции он будет вызывать все обратные вызовы по очереди.

Пример:

<Э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");

Теперь, казалось бы, осталось только прикрепить его к какому-нибудь классу.

Но это не так просто.

Событийный класс Дело в том, что когда вы пытаетесь обратиться к свойству как к функции, PHP попытается найти такую функцию в классе и выдаст ошибку, вместо того, чтобы вызвать __invoke для свойства.

Вы можете увидеть этот пример:

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");

Это означает, что нам придется убедить класс, что он хочет вызвать функцию, тем более что такого понятия не существует. Боюсь, что для этого мне придется воспользоваться костылем и буду очень признателен, если кто-нибудь предложит решение красивее этого:

<Э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); } }

Теперь остаётся только расширить Test из Eventable и наслаждаться результатом:

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");

Кстати, в качестве обратных вызовов можно указывать не только анонимные функции, но и нормально объявленные и даже методы класса!

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

Теги: #php5.3 #шаблон наблюдателя #событие #php

Вместе с данным постом часто просматривают: