需要动态地向类追加方法
我代码:<?php
class stdClass1 {
public function __call($method, $arguments) {
return call_user_func_array(Closure::bind($this->$method, $this, get_called_class()), $arguments);
}
}
class stdClass2 {
function stdRunMethod() {
$obj = new stdClass1();
$obj->test = function() {
echo 'a simple function';
};
$obj->test();
$obj2 = new stdClass1();
$obj2->test();
}
}
$obj = new stdClass2();
$obj->stdRunMethod();
问题:为什么test
方法只对stdClass1
类的第一个实例运行?如何为所有新实例附加此方法?
试试这个代替(demo):
<?php
class stdClass1 extends 'stdClass
{
private static $addedClosures = array();
public function __set($name, $value)
{
if ($value instanceof 'Closure) {
self::$addedClosures[$name] = $value;
}
else {
parent::__set($name, $value);
}
}
public function __call($method, $arguments)
{
if (isset(self::$addedClosures[$method]))
return call_user_func_array(self::$addedClosures[$method], $arguments);
return call_user_func_array($method, $arguments);
}
}
class stdClass2 extends 'stdClass
{
function stdRunMethod()
{
$obj = new stdClass1();
$obj->test = function () {
print_r('a simple function');
};
$obj->test();
$obj2 = new stdClass1();
$obj2->test();
}
}
它只运行一次的原因是stdClass1
的每个副本都维护自己的一组变量。在以下
$obj1 = new stdClass1();
$obj1->a = '1';
$obj2 = new stdClass1();
$obj2->a = '2';
echo $obj1->a;
您将得到值1
作为输出。因为在大多数情况下,它们维护不同的引用。除非你使用static
关键字。静态属性在类的所有实例之间共享,应该谨慎使用,但这就是您所考虑的。你想做的事情可以这样做
<?php
class stdClass1 {
private static $methods = [];
public function __call($method, $arguments) {
return call_user_func_array(Closure::bind($this->methods[$method], $this, get_called_class()), $arguments);
}
public function __set($name, $value) {
if (is_callable($value)) {
$this->methods[$name] = $value;
} else {
parent::__set($name, $value);
}
}
}
这里我们使用了一个静态的,定义的属性来保存所有的动态方法,我们使用了神奇的__set
属性来将这些方法设置到数组中。
也就是说,将方法动态加载到对象中是不好的。不要那样做