PHP动态添加方法到类


php dynamically append method to class

需要动态地向类追加方法

我代码:

<?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属性来将这些方法设置到数组中。

也就是说,将方法动态加载到对象中是不好的。不要那样做