Reputation: 359
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
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
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