How to add a new method to php object on the fly?

How to add a new method to an object on the fly?

$me= new stdClass; $me->doSomething=function () { echo 'I\'ve done something'; }; $me->doSomething(); //Fatal error: Call to undefined method stdClass::doSomething() 
+85
methods php
May 30 '10 at 8:49
source share
11 answers

You can use __call for this:

 class Foo { public function __call($method, $args) { if (isset($this->$method)) { $func = $this->$method; return call_user_func_array($func, $args); } } } $foo = new Foo(); $foo->bar = function () { echo "Hello, this function is added at runtime"; }; $foo->bar(); 
+88
May 30 '10 at 9:00
source share

With PHP7 you can use anonymous classes

 $myObject = new class { public function myFunction(){} }; $myObject->myFunction(); 

PHP RFC: Anonymous Classes

+36
Mar 04 '16 at 18:01
source share

Using a simple __call to allow the addition of new methods at runtime has the main drawback that these methods cannot use the $ this instance link. Everything works fine until the added methods use $ this in the code.

 class AnObj extends stdClass { public function __call($closure, $args) { return call_user_func_array($this->{$closure}, $args); } } $a=new AnObj(); $a->color = "red"; $a->sayhello = function(){ echo "hello!";}; $a->printmycolor = function(){ echo $this->color;}; $a->sayhello();//output: "hello!" $a->printmycolor();//ERROR: Undefined variable $this 

To solve this problem, you can rewrite the template this way

 class AnObj extends stdClass { public function __call($closure, $args) { return call_user_func_array($this->{$closure}->bindTo($this),$args); } public function __toString() { return call_user_func($this->{"__toString"}->bindTo($this)); } } 

So you can add new methods that can use instance reference

 $a=new AnObj(); $a->color="red"; $a->sayhello = function(){ echo "hello!";}; $a->printmycolor = function(){ echo $this->color;}; $a->sayhello();//output: "hello!" $a->printmycolor();//output: "red" 
+17
Apr 30 '14 at 23:11
source share

Update: The approach given here has a big drawback: the new function is not a fully qualified member of the class; $this not in the method when calling this method. This means that you need to pass the object to the function as a parameter if you want to work with data or functions from an object instance! In addition, you will not be able to access private or protected class members from these functions.

Good question and smart idea using new anonymous features!

Interestingly, this works: Replace

 $me->doSomething(); // Doesn't work 

by call_user_func on the function itself:

 call_user_func($me->doSomething); // Works! 

what doesn't work is the β€œright” way:

 call_user_func(array($me, "doSomething")); // Doesn't work 

if called this way, PHP requires the method to be declared in the class definition.

Is this a private / public / protected visibility issue?

Update: None. It is not possible to call a function in the usual way, even from within the class, so this is not a visibility problem. Passing the actual function to call_user_func() is the only way I can do this work.

+12
May 30, '10 at 9:00 a.m.
source share

Here is a simple class that allows you to set up an anonymous function. This is an optimized class https://gist.github.com/nickunderscoremok/5857846

 <?php class stdObject { public function __construct(array $arguments = array()) { if (!empty($arguments)) { foreach ($arguments as $property => $argument) { if ($argument instanceOf Closure) { $this->{$property} = $argument; } else { $this->{$property} = $argument; } } } } public function __call($method, $arguments) { if (isset($this->{$method}) && is_callable($this->{$method})) { return call_user_func_array($this->{$method}, $arguments); } else { throw new Exception("Fatal error: Call to undefined method stdObject::{$method}()"); } } } $person = new stdObject(array( "name" => "nick", "age" => 23, "friends" => array("frank", "sally", "aaron"), "sayHi" => function() { return "Hello there"; } )); $person->sayHi2 = function() { return "Hello there 2"; }; $person->test = function() { return "test"; }; var_dump($person->name, $person->test(), $person->sayHi2()); ?> 
+3
Feb 19 '14 at 18:39
source share

you can also save functions in an array:

 <?php class Foo { private $arrayFuncs=array();// array of functions // public function addFunc($name,$function){ $this->arrayFuncs[$name] = $function; } // public function callFunc($namefunc,$params=false){ if(!isset($this->arrayFuncs[$namefunc])){ return 'no function exist'; } if(is_callable($this->arrayFuncs[$namefunc])){ return call_user_func($this->arrayFuncs[$namefunc],$params); } } } $foo = new Foo(); //Save function on array variable with params $foo->addFunc('my_function_call',function($params){ return array('data1'=>$params['num1'],'data2'=>'qwerty','action'=>'add'); }); //Save function on array variable $foo->addFunc('my_function_call2',function(){ return 'a simple function'; }); //call func 1 $data = $foo->callFunc('my_function_call',array('num1'=>1224343545)); var_dump($data); //call func 2 $data = $foo->callFunc('my_function_call2'); var_dump($data); ?> 
+2
Jul 16 '15 at 21:47
source share

Without the __call solution __call you can use bindTo (PHP> = 5.4) to call the method with $this > associated with $me as follows:

 call_user_func($me->doSomething->bindTo($me, null)); 

A full script might look like this:

 $me = new stdClass; // Property for proving that the method has access to the above object: $me->message = "I\'ve done something"; $me->doSomething = function () { echo $this->message; }; call_user_func($me->doSomething->bindTo($me)); // "I've done something" 

Alternatively, you can assign the associated function to a variable and then call it without call_user_func :

 $f = $me->doSomething->bindTo($me); $f(); 
+1
Jan 03 '17 at 14:17
source share

To learn how to do this with eval, you can take a look at my PHP microstructure, Halcyon, which is available on github . It is small enough for you to understand it without any problems - focus on the HalcyonClassMunger class.

0
May 30 '10 at 8:57
source share

There is an https://stackoverflow.com/a/166954/2/16/4/4/4/9/2/2/2/2/2/16.htm where there is an https://stackoverflow.com/a/3148168/ which is only possible if certain design patterns are implemented.

The only way is to use classkit , an experimental php extension. (also in the message)

Yes, you can add a method to the PHP class after defining it. You want to use classkit, which is an "experimental" extension. It seems that this extension is not enabled by default, so it depends on if you can compile your own PHP binary or load PHP libraries if on windows (for an instance of Dreamhost PHP binaries allow, and they are quite easy to configure).

0
May 30 '10 at 9:05
source share

I would never use it, the syntax is terrible, but you can add an object that has functions for the property. Statically, when it is possible to save the input of a new and () ;

 class SomeFuncs{ static function a(){ /* do something */ }} $o = new stdClass(); $o->f = SomeFuncs; $o->f::a(); 
0
Feb 18 '17 at 13:28
source share

karim79 responds, however, it stores anonymous functions inside the method properties, and its declarations may overwrite existing properties with the same name or do not work if the existing private property causes the fatal error object to be inapplicable. I think storing them in a separate array and using a setter is a cleaner solution. The injector installation method can be added to each object automatically using traits .

PS Of course, this is a hack that cannot be used, because it violates the open, closed SOLID principle.

 class MyClass { //create array to store all injected methods private $anon_methods = array(); //create setter to fill array with injected methods on runtime public function inject_method($name, $method) { $this->anon_methods[$name] = $method; } //runs when calling non existent or private methods from object instance public function __call($name, $args) { if ( key_exists($name, $this->anon_methods) ) { call_user_func_array($this->anon_methods[$name], $args); } } } $MyClass = new MyClass; //method one $print_txt = function ($text) { echo $text . PHP_EOL; }; $MyClass->inject_method("print_txt", $print_txt); //method $add_numbers = function ($n, $e) { echo "$n + $e = " . ($n + $e); }; $MyClass->inject_method("add_numbers", $add_numbers); //Use injected methods $MyClass->print_txt("Hello World"); $MyClass->add_numbers(5, 10); 
0
Sep 23 '17 at 2:27 on
source share



All Articles