如何不使用继承来扩展一个类
最重要文档 译注:这篇文档虽然很短,却极其重要,后面会有机会同大家深度分享。
要允许多个类向另一个类中添加方法,你可以在想要扩展的类中按照下例来定义 __call()
魔术方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
class Foo
{
// ...
public function __call($method, $arguments)
{
// create an event named 'foo.method_is_not_found'
// 创建一个名为 'foo.method_is_not_found' 的事件
$event = new HandleUndefinedMethodEvent($this, $method, $arguments);
$this->dispatcher->dispatch('foo.method_is_not_found', $event);
// no listener was able to process the event? The method does not exist
// 没有监听能够处理此事件? 那么该方法不存在
if (!$event->isProcessed()) {
throw new \Exception(sprintf('Call to undefined method %s::%s.', get_class($this), $method));
}
// return the listener returned value
// 返回“监听器所返回的值”
return $event->getReturnValue();
}
} |
这个类用到了一个特殊的 HandleUndefinedMethodEvent
事件类,也应当被创建。这是个通用类,每当你需要使用这种模式的“类扩展”时,都可以复用它:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
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;
}
/**
* Sets the value to return and stops other listeners from being notified
* 设置返回值,同时中止向其他监听发送通知
*/
public function setReturnValue($val)
{
$this->returnValue = $val;
$this->isProcessed = true;
$this->stopPropagation();
}
public function getReturnValue()
{
return $this->returnValue;
}
public function isProcessed()
{
return $this->isProcessed;
}
} |
接下来,创建一个监听类,用于监听 foo.method_is_not_found
事件,并添加 bar()
方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
class Bar
{
public function onFooMethodIsNotFound(HandleUndefinedMethodEvent $event)
{
// only respond to the calls to the 'bar' method
// 只对 'bar'方法的调用 进行响应
if ('bar' != $event->getMethod()) {
// allow another listener to take care of this unknown method
// 允许另一个监听接管这个未知方法
return;
}
// the subject object (the foo instance)
// 被操作对象(主题对象。foo实例)
$foo = $event->getSubject();
// the bar method arguments
// bar方法的参数
$arguments = $event->getArguments();
// ... do something / 做一些事
// set the return value
// 设置返回值
$event->setReturnValue($someValue);
}
} |
最后,通过把 foo.method_is_not_found
事件连同 Bar
实例一起注册(到dispatcher),即可向 Foo
类中添加 bar
方法:
1 2 |
$bar = new Bar();
$dispatcher->addListener('foo.method_is_not_found', array($bar, 'onFooMethodIsNotFound')); |