容許多個類將方法添加到另一個(至關於總控);咱們能夠在擴展類中使用魔術方法 __call()
this
class Foo { public $dispatcher; public function __construct(EventDispatcher $dispatcher) { $this->dispatcher = $dispatcher; } public function __call($method, $arguments) { // 建立一個名稱爲 'foo.method_is_not_found'的事件 $event = new HandleUndefinedMethodEvent($this, $method, $arguments); $this->dispatcher->dispatch('foo.method_is_not_found', $event); // 若是沒有監聽者處理該事件證實該方法不存在 if (!$event->isProcessed()) { throw new \Exception(sprintf('Call to undefined method %s::%s.', get_class($this), $method)); } // 返回監聽者設置的返回值 return $event->getReturnValue(); } }
建立事件對象類spa
use Symfony\Component\EventDispatcher\Event; class HandleUndefinedMethodEvent extends Event { protected $subject; protected $method; protected $arguments; protected $returnValue; protected $isProcessed = false; public function __construct($subject, $method, $arguments) { $this->subject = $subject; $this->method = $method; $this->arguments = $arguments; } public function getSubject() { return $this->subject; } public function getMethod() { return $this->method; } public function getArguments() { return $this->arguments; } /** * 若是方法已經找到;設置返回值;且中止事件傳播給其它監聽者 */ public function setReturnValue($val) { $this->returnValue = $val; $this->isProcessed = true; //標識爲已處理;證實方法存在; $this->stopPropagation(); //中止事件傳播; } public function getReturnValue() { return $this->returnValue; } public function isProcessed() { return $this->isProcessed; } }
添加監聽者類code
class Bar { public function onFooMethodIsNotFound(HandleUndefinedMethodEvent $event) { // 僅僅調用bar方法的時候該監聽者才處理; if ('bar' != $event->getMethod()) { //讓其餘的監聽者處理未知的方法 return; } //主題對像(foo 實例) $foo = $event->getSubject(); // 獲取bar方法參數 $arguments = $event->getArguments(); // ... do something // 設置返回值 $event->setReturnValue("aaaaaa"); } }
public function testNotMethodEventAction() { $bar = new Bar(); $dispatcher = new EventDispatcher(); $dispatcher->addListener("foo.method_is_not_found", array($bar, 'onFooMethodIsNotFound')); $foo = new Foo($dispatcher); $foo->bar(); $foo->xxx(); return new Response("xxxxaazzz"); }
這個例子實際上是經過foo經過事件(不是使用繼承)來調用bar和其餘監聽中的某些方法對象