允许多个类将方法添加到另外一个(相当于总控);我们可以在扩展类中使用魔术方法 __call()
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();
}
}
创建事件对象类
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;
}
}
添加监听者类
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和其他监听中的某些方法