我试图找到一种方法来执行一些代码来改变对象方法的结果,而不实际接触对象的代码。我想到的一种方法是使用修饰符:
class Decorator {
private $object;
public function __construct($object) {
if (!is_object($object)) {
throw new Exception("Not an object");
}
$this->object = $object;
}
protected function doSomething(&$val) {
$val .= "!!";
}
public function __call($name, $arguments) {
$retVal = call_user_func_array(array($this->object, $name), $arguments);
$this->doSomething($retVal);
return $retVal;
}
}
class Test extends BaseTest {
public function run() {
return "Test->run()";
}
}
$o = new Decorator(new Test());
$o->run();
这样它将正常工作,但它有一个缺点,这使得它现在对我来说是不可用的-它需要用new Decorator(new Test())
替换new Test()
的所有行,这正是我想要避免的-大量干扰现有代码。也许我可以在基类中做些什么?
在PHP中不能简单地重载东西。所以你想要的不能实现。但你现在陷入困境的事实是,你的设计是有缺陷的。或者如果这不是你的代码,设计你必须使用的代码(我理解你的痛苦)。
如果你不能做你想做的,那是因为你的代码是紧密耦合的。也就是说,你在类中使用new
关键字,而不是将它们(依赖注入)注入到需要它的类/方法中。
除了不能轻松地交换类之外,由于紧密耦合,您还将花费大量时间轻松测试您的单元。
为了完整性(对于将来可能的读者):如果特定的类已经被命名空间,并且允许您更改名称空间,那么您可能已经考虑更改名称空间了。然而,这并不是一个很好的做法,因为它可能会与自动装弹器发生关系。PSR-0就是一个例子。但考虑到你两种方式都做不到,我不认为你想要的是可能的。注:你不应该真的使用这个"解决方案"。
更新2
看起来在某个时候有一些重载扩展(way wayway back),但我唯一发现的是一些错误报告。不要指望它现在还能正常工作。-)在PHP中根本没有真正的重载。
发现了一些东西(一个不再工作的死项目,允许类重载):http://pecl.php.net/package/runkit
可能是另一个项目(当然也死了):http://pecl.php.net/package/apd
我不是PHP程序员,但我认为AOP是您正在寻找的。您可以尝试一些框架,例如在这个答案中列出的。
摘自维基百科关于装饰器模式的文章:
- 将原来的"Decorator"类子类化为"Component"类
所以我认为你应该保持类被装饰为私有的,只暴露已经装饰的类