0

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?

4
  • 1
    Because you only assign the function to the property of the first object. When you modify the object, you don't modify the class. Commented Aug 22, 2016 at 9:19
  • Yes. This way I can add methods to class instances. But I need dynamically add methods directly to the classes. Is it possible? Commented Aug 22, 2016 at 9:21
  • Perhaps using Reflection it is possible. Or maybe you can create a container to add the property after object creation. Commented Aug 22, 2016 at 9:26
  • Possible duplicate of How to add a new method to a php object on the fly? Commented Aug 22, 2016 at 9:29

2 Answers 2

2

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

    }
Sign up to request clarification or add additional context in comments.

Comments

1

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

3 Comments

Why you use $this-> to call static array?
Just used to it. Feel free to use self:: instead
seems to give nearly the same errors as the original question. The selected answer works.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.