V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
niuoh
V2EX  ›  PHP

怎么给 PHP 对象动态添加方法

  •  
  •   niuoh · 2016-12-01 17:43:19 +08:00 · 5392 次点击
    这是一个创建于 2704 天前的主题,其中的信息可能已经有所发展或是发生改变。

    网上查了一下给 PHP 类动态添加方法需要类中自带__call 魔术方法
    如果类 class A{}
    就这样 那怎么动态添加方法呢
    支持这样:
    $a=new A;
    $a->test=function(){};
    $a->test();

    8 条回复    2016-12-30 17:12:19 +08:00
    Jakesoft
        1
    Jakesoft  
       2016-12-01 17:47:00 +08:00
    call_user_func($m->test);
    ParallelMao
        2
    ParallelMao  
       2016-12-01 17:59:30 +08:00   ❤️ 1
    想来你应该是需要这个的。

    http://php.net/manual/zh/closure.bind.php
    RH
        3
    RH  
       2016-12-01 19:08:47 +08:00
    greatonce
        4
    greatonce  
       2016-12-01 19:57:56 +08:00
    class Test{
    public $_methodContainer = [];

    public function __call($method,$value)
    {
    if(isset($this->_methodContainer[$method])) {
    return call_user_func_array($this->_methodContainer[$method], $value);
    }
    throw new Exception("The specify method cannot be found", 1);
    }
    }

    // define a new method.
    function newMethod($s) {return $s.'hello world';}

    $test = new Test;
    $test->_methodContainer['test'] = 'newMethod';
    echo $t->test('你好 ');
    feiyuanqiu
        5
    feiyuanqiu  
       2016-12-01 20:27:05 +08:00
    class Test
    {
    private $dynamicMethods = [];

    public function __get($name)
    {
    return isset($this->dynamicMethods[ $name ]) ? $this->dynamicMethods[ $name ] : null;
    }

    public function __set($name, $value)
    {
    if ($this->isClosure($value)) {
    $this->dynamicMethods[ $name ] = Closure::bind($value, $this, self::class);;
    }
    }

    private function isClosure($value)
    {
    return is_callable($value) && get_class($value) === \Closure::class;
    }

    public function __isset($name)
    {
    return isset($this->dynamicMethods[ $name ]);
    }

    public function __call($name, $arguments)
    {
    if (!isset($this->dynamicMethods[ $name ])) {
    trigger_error('Call to undefined method ' . self::class . "::{$name}", E_USER_ERROR);
    }

    return call_user_func($this->dynamicMethods[ $name ], $arguments);
    }
    }

    $a = new Test();
    $a->test = function () {
    var_dump($this->dynamicMethods);
    };
    $a->test();
    niuoh
        6
    niuoh  
    OP
       2016-12-02 10:06:58 +08:00
    找到正解了 我的意思是 class A{} 类里什么都没有也支持动态添加类方法 且支持$a->test();这样调用
    方法如下:
    class merge_objs{
    private $classArr = array();

    function __construct() {
    $this -> classArr = func_get_args();
    }

    function __get($s) {
    foreach($this-> classArr as $c) {
    if (property_exists($c, $s)) {
    return $c -> $s;
    }
    }
    }

    function __call($fn,$args) {
    foreach($this-> classArr as $c) {
    if (method_exists($c, $fn)) {
    return call_user_func_array(array($c,$fn),$args);
    }
    }
    }
    }

    class A{}

    class B{
    public function test(){
    echo test;
    }
    }

    $a=new merge_objs(new A,new B);
    $a->test();
    v2song
        7
    v2song  
       2016-12-02 11:50:43 +08:00
    可以学习一下 Laravel Macroable 的思想
    ```php
    class Test
    {
    use Macroable;
    }

    Test::macro('say', function ($word) {
    echo $word;
    });

    $test = new Test();

    $test->say('hello');
    ```
    zhaohehe
        8
    zhaohehe  
       2016-12-30 17:12:19 +08:00
    $a = new A;
    $b = function(){
    //...
    };

    $b->call($a);

    php7 的用法,匿名函数的 call()
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2960 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 46ms · UTC 14:01 · PVG 22:01 · LAX 07:01 · JFK 10:01
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.