作者:老王

动态语言的必杀技之一就是能动态修改对象。不过PHP在这方面有缺陷,不能随心所欲,比如说不能很方便的给对象动态添加一个新方法。不过通过魔术方法可以在一定程度上改善这个问题,这也不算什么新鲜事儿,很多PHP项目都做过有益的尝试,比如CakePHP在Model的Behavior中的尝试,不过今天要说的方式在魔术方法的基础上引入了PHP5.3的新功能:closure,从而让实现效果更像Javascript这种prototype风格。

代码(at pastebin.com):

01 abstract class ClassAbstract
02 {
03 protected $closures = array();
04
05 public function __get($name)
06 {
07 if (isset($this->closures[$name])) {
08 return $this->closures[$name];
09 }
10
11 throw new Exception(‘Undefined property: ‘ . $name);
12 }
13
14 public function __set($name, $value)
15 {
16 if (get_class($value) == ‘Closure’) {
17 $this->closures[$name] = $value;
18 } else {
19 $this->$name = $value;
20 }
21 }
22
23 public function __call($name, $arguments)
24 {
25 if (isset($this->closures[$name])) {
26 array_unshift($arguments, $this);
27 return call_user_func_array($this->closures[$name], $arguments);
28 }
29
30 throw new Exception(‘Undefined method: ‘ . $name);
31 }
32 }
33
34 class Foo extends ClassAbstract
35 {
36 private $attribute = ‘hello, world.’;
37
38 public function attribute()
39 {
40 return $this->attribute;
41 }
42 }
43
44 // hello, world. I’m LaoWang.
45
46 $foo = new Foo();
47
48 $foo->test = function($self, $name) {
49 return $self->attribute() . ” I’m {$name}.”;
50 };
51
52 echo $foo->test(‘LaoWang’);

在动态添加方法的时候,我们使用这样的语法:

$foo->new_function = function($self, …) { … };

具体点说,对象本身($this)要作为第一个参数($self)传递进去,不过在调用方法的时候可以无视这个参数,程序会自动传入$this,这虽然多少有点不透明,但也是无奈之举,况且,如果你喜欢Python的实现方式,说不定还会觉得这个方式很亲切。

当然,如果你想替换旧方法,对PHP而言,没戏!能添加新方法就感激不尽了,大家就知足吧。

来自yaronspace.cn  本文链接:http://yaronspace.cn/blog/archives/745