改变对象方法结果的方法

时间:2013-01-04 09:18:30

标签: php oop decorator

我试图找到一种方法来执行一些代码来改变对象方法的结果而不实际触及对象的代码。我提出的一种方法是使用装饰器:

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

3 个答案:

答案 0 :(得分:3)

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

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

除了不能轻易交换课程外,由于紧密耦合,你也可以轻松地测试你的单位。

<强>更新

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

<强> UPDATE2

看起来某些时候有一些过载扩展(方式方式回来),但我have found唯一关于它的是some bug report。并且不要指望它现在仍然有效。 ;-) PHP中没有真正的重载。

找到了一些东西(一个不再有效的死项目,可以实现类重载):http://pecl.php.net/package/runkit

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

答案 1 :(得分:0)

我不是PHP程序员,但我认为AOP正是您所寻找的。您可以尝试一些框架,例如此answer中列出的。

答案 2 :(得分:0)

来自Wikipedia article on the decorator pattern

  
      
  1. 将原始的“Decorator”类子类化为“Component”类
  2.   

所以我认为你应该让这个班级被私人装饰,只露出已装饰的班级。