2

我试图找到一种方法来执行一些代码来更改对象方​​法的结果,而无需实际接触对象的代码。我想出的一种方法是使用装饰器:

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 Test()with替换所有行,new Decorator(new Test())这正是我想要避免的 - 大量干预现有代码。也许我可以在基类中做些什么?

4

3 回答 3

3

一个不是简单地重载 PHP 中的东西。所以你想做的事是做不到的。但是你现在遇到麻烦的事实是一个很大的说明你的设计是有缺陷的。或者,如果不是您的代码设计,您必须使用的代码(我感到您的痛苦)。

如果你不能做你想做的事,那是因为你的代码紧密耦合了。即,您new在类中使用关键字,而不是将它们(依赖注入)注入到需要它的类/方法中。

除了不能轻松地交换类之外,由于紧密耦合,您还可以轻松地测试您的单元。

更新

为了完整性(对于未来可能的读者):如果特定类已经被命名空间并且您被允许更改命名空间,那么您可以考虑更改命名空间。然而,这并不是一个很好的做法,因为它可能会与例如自动加载器一起使用。PSR-0就是一个例子。但是考虑到你不能这样做,我看不出你想要什么。PS你不应该真正使用这个“解决方案”。

更新2

看起来某个时候(很久以前)有一些过载扩展,但我发现的唯一一件事就是一些错误报告。不要指望它现在仍然有效。;-) PHP 中根本没有真正的重载。

找到了一些东西(一个不再工作的死项目,它启用了类重载): http: //pecl.php.net/package/runkit

可能是另一个项目(当然也死了): http: //pecl.php.net/package/apd

于 2013-01-04T09:22:44.020 回答
0

我不是 PHP 程序员,但我认为AOP是您正在寻找的。您可以尝试一些框架,例如在这个答案中列出。

于 2013-01-04T09:25:18.330 回答
0

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

  1. 将原始“装饰器”类子类化为“组件”类

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

于 2013-01-04T09:29:40.047 回答