Задача — сделать на PHP эвенты а-ля C# т.е. произвольный объект может генерировать события. Другие объекты могут на эти события подписываться непосредственно у экземпляра генерирующего объекта.
Основное отличие от того что видел ранее — строгая проверка навешиваемого хука. Проверяется наличие метода, количество его аргументов, etc…
Когда в PHP повится метод ReflectionMethod::getClosure() (который, судя по всему, не войдет в 5.3 хотя ранее присутствовал в документации) можно будет отказаться от использования call_user_func_array и использовать замыкания, заменив строку 63 на следующий код
А строку в функции fireEvent на следующее…
UPD: Забытый класс EventArgument
Основное отличие от того что видел ранее — строгая проверка навешиваемого хука. Проверяется наличие метода, количество его аргументов, etc…
- <?php
-
- abstract class EventClass {
-
- /**
- * Хранятся колбэки для событий
- *
- * @var array
- */
- protected $eventRecievers = array();
-
- /**
- * События - массив строк
- *
- * @var array
- */
- protected $myEvents = array();
-
- /**
- * Сеттер для событий
- *
- * @param string $prop Событие
- * @param callback $val Колбэк
- */
- function __set($prop, $val)
- {
- if(in_array($prop, $this->myEvents))
- $this->attachEvent($prop, $val);
- else
- throw new Exception("Property {$prop} is not found or read only");
- }
-
- /**
- * Caller overloader
- *
- * @param string $name Имя вызываемого метода
- * @param array $args Массив аргументов
- */
- function __call($name, $args)
- {
- if(in_array($name, $this->myEvents))
- $this->fireEvent($name, $args);
- else
- throw new Exception("No such event or bad arguments given");
- }
-
- /**
- * Присоединяет хэндлер события к выбранному событию
- *
- * @param srting $event Событие
- * @param callback $callback Колбэк
- */
- protected function attachEvent($event, $callback)
- {
- if(in_array($event, $this->myEvents))
- {
- if(is_array($callback) && is_object($callback[0]) && is_string($callback[1]))
- {
- $reflection = new ReflectionClass(get_class($callback[0]));
- try {
- $method = $reflection->getMethod($callback[1]);
- if($method->getNumberOfParameters() == 1)
- $this->eventRecievers[$event][]=$callback;
- else
- throw new Exception(get_class($callback[0])."::{$callback[1]} have more than 1 arguments");
- }
- catch(Exception $e) {
- throw new Exception("Class ".get_class($callback[0])." doesn't have method {$callback[1]}");
- }
- }
- else
- throw new Exception("Wrong callback format");
- }
- else
- throw new Exception(__CLASS__." has no event {$event}");
- }
-
- /**
- * "Зажигает" событие
- *
- * @param string $event
- * @param EventArgument $argument
- */
- protected function fireEvent($event, $argument)
- {
- if(in_array($event, $this->myEvents))
- {
- if(is_array($this->eventRecievers[$event]) && count($this->eventRecievers[$event]))
- foreach($this->eventRecievers[$event] as $callback)
- call_user_func_array($callback, array(new EventArgument($this, $argument)));
- }
- else
- throw new Exception(__CLASS__." have no event {$event}");
- }
-
- }
-
- class CanGenerateEvents extends EventClass {
-
- protected $myEvents = array('onSomething', 'onSomethingElse');
-
- // Code goes here
-
- function makeSomething()
- {
- // Doing something useful...
-
- $this->onSomething("someText");
- }
-
- }
-
- class WantSomething {
-
- function recieveHere(EventArgument $arg)
- {
- echo $arg->argument;
- }
-
- }
-
- $w = new WantSomething();
- $g = new CanGenerateEvents();
-
- $g->onSomething = array($w, 'recieveHere');
-
- ?>
* This source code was highlighted with Source Code Highlighter.
Когда в PHP повится метод ReflectionMethod::getClosure() (который, судя по всему, не войдет в 5.3 хотя ранее присутствовал в документации) можно будет отказаться от использования call_user_func_array и использовать замыкания, заменив строку 63 на следующий код
$this->eventRecievers[$event][]=$method->getClosure();
* This source code was highlighted with Source Code Highlighter.
А строку в функции fireEvent на следующее…
$callback(new EventArgument($this, $argument));
* This source code was highlighted with Source Code Highlighter.
UPD: Забытый класс EventArgument
class EventArgument {
public $caller = null;
public $argument = null;
function __construct($caller, $argument = null)
{
$this->caller = $caller;
$this->argument = $argument;
}
}
* This source code was highlighted with Source Code Highlighter.