stdex
stdex

Reputation: 359

php dynamically append method to class

Need dynamically append method to class.

My code:

<?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();

Question: why test method run only for first instance of stdClass1 class? How to append this method for all new instances?

Upvotes: 0

Views: 1010

Answers (2)

Ahmad Hajjar
Ahmad Hajjar

Reputation: 1853

try this instead (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();
        }

    }

Upvotes: 2

Gareth Parker
Gareth Parker

Reputation: 5062

The reason it only runs once is that each copy of stdClass1 maintains their own set of variables. In the following

$obj1 = new stdClass1();
$obj1->a = '1';

$obj2 = new stdClass1();
$obj2->a = '2';

echo $obj1->a;

You'll get the value 1 as the output. Because in most cases they maintain different references. Unless you use the static keyword. Static properties are shared between all instances of the class, and should be used carefully, but that's what you're thinking of. What you're thinking of can be done like this

<?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);
        }
    }
}

Here we're using a static, defined property to hold all of the dynamic methods, and we're using the magic __set property to set the methods in to the array.

That being said, dynamically loading methods in to an object is bad. Don't do that

Upvotes: 1

Related Questions