改变object'方法结果的方法


Way to change results of object's methods

我试图找到一种方法来执行一些代码来改变对象方法的结果,而不实际接触对象的代码。我想到的一种方法是使用修饰符:

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是您正在寻找的。您可以尝试一些框架,例如在这个答案中列出的。

摘自维基百科关于装饰器模式的文章:

  1. 将原来的"Decorator"类子类化为"Component"类

所以我认为你应该保持类被装饰为私有的,只暴露已经装饰的类