【问题标题】:php dynamically append method to classphp动态地将方法附加到类
【发布时间】:2016-12-28 18:28:02
【问题描述】:

需要动态地将方法附加到类。

我的代码:

<?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 类的第一个实例运行?如何为所有新实例附加此方法?

【问题讨论】:

  • 因为您只将函数分配给第一个对象的属性。修改对象时,不会修改类。
  • 是的。这样我可以向类实例添加方法。但我需要将方法直接动态添加到类中。有可能吗?
  • 也许使用反射是可能的。或者,也许您可​​以创建一个容器以在对象创建后添加属性。

标签: php


【解决方案1】:

试试这个(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();
        }

    }

【讨论】:

    【解决方案2】:

    它只运行一次的原因是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 属性将方法设置到数组中。

    话虽如此,将方法动态加载到对象中是不好的。不要那样做

    【讨论】:

    • 为什么要用$this->来调用静态数组?
    • 习惯了。请随意使用self::
    • 似乎给出了与原始问题几乎相同的错误。所选答案有效。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-16
    • 2022-11-24
    • 1970-01-01
    • 2012-03-15
    • 1970-01-01
    • 2012-03-27
    相关资源
    最近更新 更多