Is there a way to dynamically invoke a method in the same class for PHP? I don't have the syntax right, but I'm looking to do something similar to this:
$this->{$methodName}($arg1, $arg2, $arg3);
There is more than one way to do that:
$this->{$methodName}($arg1, $arg2, $arg3);
$this->$methodName($arg1, $arg2, $arg3);
call_user_func_array(array($this, $methodName), array($arg1, $arg2, $arg3));
You may even use the reflection api http://php.net/manual/en/class.reflection.php
You can use the Overloading in PHP:
Overloading
class Test {
private $name;
public function __call($name, $arguments) {
echo 'Method Name:' . $name . ' Arguments:' . implode(',', $arguments);
//do a get
if (preg_match('/^get_(.+)/', $name, $matches)) {
$var_name = $matches[1];
return $this->$var_name ? $this->$var_name : $arguments[0];
}
//do a set
if (preg_match('/^set_(.+)/', $name, $matches)) {
$var_name = $matches[1];
$this->$var_name = $arguments[0];
}
}
}
$obj = new Test();
$obj->set_name('Any String'); //Echo:Method Name: set_name Arguments:Any String
echo $obj->get_name();//Echo:Method Name: get_name Arguments:
//return: Any String
Just omit the braces:
$this->$methodName($arg1, $arg2, $arg3);
You can also use call_user_func() and call_user_func_array()
If you're working within a class in PHP, then I would recommend using the overloaded __call function in PHP5. You can find the reference here.
Basically __call does for dynamic functions what __set and __get do for variables in OO PHP5.
In my case.
$response = $client->{$this->requestFunc}($this->requestMsg);
Using PHP SOAP.
You can store a method in a single variable using a closure:
class test{
function echo_this($text){
echo $text;
}
function get_method($method){
$object = $this;
return function() use($object, $method){
$args = func_get_args();
return call_user_func_array(array($object, $method), $args);
};
}
}
$test = new test();
$echo = $test->get_method('echo_this');
$echo('Hello'); //Output is "Hello"
EDIT: I've edited the code and now it's compatible with PHP 5.3. Another example here
Still valid after all these years! Make sure you trim $methodName if it is user defined content. I could not get $this->$methodName to work until I noticed it had a leading space.
Related
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Use a variable to define a PHP function
Use Variable as Function Name in PHP
I want to perform a conditional function call but I don't necessarily know what what the function will be, so that would be a long switch.
For example;
$userSelection = "calculator"; /* or "stocks" or whatever widget */
$widget->get_widget($userSelection);
public function __construct($userSelection){
/* pseudo code */
call function $userSelection();
}
public function calculator(){
/* Get Calculator */
}
Sure there is. This feature is called variable functions:
$functionName = "strlen";
$length = $$functionName("Hello world!");
The $$var(...) syntax is convenient, but it will only work with free functions. If you want to call a class method this way, you will need to use call_user_func or call_user_func_array (these functions can also handle the "free function" case).
Look at the call-user-func function. This allows you to call another function, e.g.
call_user_func('calculator')
call_user_func($userSelection);
http://php.net/manual/en/function.call-user-func.php
Take a look at this php functions:
call_user_func(): http://php.net/manual/de/function.call-user-func.php
call_user_func_array(): http://www.php.net/manual/de/function.call-user-func-array.php
create_function(): http://www.php.net/manual/de/function.create-function.php
There is also a direct (though ugly) execution syntax:
function some_func(args) {...}
$function_name='some_func';
$$function_name(args2);
You can use call_user_func() for that, like this:
$userSelection = "calculator";
call_user_func($userSelection[, $param1, $param2, ...]);
call_user_func_array($userSelection, $params);
If it's just a function you're after then using this should solve your problems
$function = "echo";
$$function "fooBar";
If it's a class method that you want to keep flexible use magic method __call() which will allow you to use method names that are not pre-defined.
__call() is triggered when invoking inaccessible methods in an object context.
i.e.
class Foo {
public function __call($name, $arguments) {
echo $name;
}
}
$foo = new Foo();
$foo->bar(); // will echo "bar"
PHP built-in function 'eval' can do everything, but beware of injection.
$var = "somefunction";
eval("$var();");
http://php.net/manual/en/function.eval.php
It's pretty simple if that's what you mean.
function calculator() {
echo 'foo';
}
$userSelection = "calculator";
if (function_exists($userSelection)) {
$userSelection();
}
Or within a class like in your example:
class widget {
public function __construct($userSelection) {
echo 'constructed widget<br>';
if (function_exists($userSelection)) {
$this->$userSelection();
}
}
public function calculator() {
echo 'bar';
}
}
$userSelection = "calculator";
$widget = new widget($userSelection);
Or from outside a class when the function is part of the class.
class widget {
public function calculator() {
echo 'bar';
}
}
$widget = new widget();
$userSelection = "calculator";
$widget->$userSelection();
I would work with if/else statements though to determine the function to be called just to be sure that only valid functions are executed (do you sanitize the user selection or do you just get it from a $_POST? The latter would be a very bad idea).
You can do following :
$var = 'abc';
switch ($var) {
case 'abc':
$result = $var('test param');
echo $result;
break;
default :
echo 'default';
break;
}
function abc($data) {
return $data;
}
I get this error when I try to call $func('something'):
if(($object instanceof MyObject) && (method_exists($object, 'foo'))){
$func = array(&$object, 'foo');
}else{
$func = 'fallback_foo';
}
...
echo $func('something');
What's wrong with my code?
Obviously I cannot make $func a string because it's a method specific to a object...
but an array with the method name and object should work right?
Use call_user_func() or call_user_func_array(). Both support regular functions and method calls:
echo call_user_func($func, 'something');
echo call_user_func_array($func, array('something'));
it is possible to assign to a class variable a function at runtime to be executed? a kind of "function pointer" like C
something like this: (this won't work because sum is out of the scope of A, but this is the pattern i mean)
class A {
public $function_name;
public functon run($arg1,$arg2){
$function_name($arg1,$arg2);
}
}
function sum($a,$b){
echo $a+$b;
}
$a=new A();
$a->function_name='sum';
$a->run();
[edit]
i know there is "call_user_func" but it need as i understand to have the function in the scope or use a public class method
You could use an anonymous function if you use PHP >5.3.0:
$sum = function($a, $b) {
return $a+$b;
}
$a->function_name = $sum;
Using call_user_func_array:
<?php
class A {
public $function_name;
public function run($arg1,$arg2){
return call_user_func_array( $this->function_name, array($arg1, $arg2 ) );
}
}
function sum($a,$b){
return $a+$b;
}
$a=new A();
$a->function_name= 'sum';
var_dump( $a->run(1,1) ); //2
?>
It works regardless of scope. You just gotta call it using call_user_func. I also fixed a couple of typos in your example.
<?php
class A {
public $function_name;
public function run($arg1, $arg2) {
call_user_func($this->function_name, $arg1, $arg2);
}
}
function sum($a, $b){
echo $a + $b;
}
$a = new A();
$a->function_name = 'sum';
$a->run(2, 3);
?>
Live example
Another way is to make use variable variables (applicable to object method)
public static function sum($arg1, $arg2)
{
..
}
public function run($arg1, $arg2)
{
$func = $this->function_name;
$func( $arg1, $arg2); <-- procedural call
self::$func($arg1, $arg2); <-- static method call
}
Use any variation of the Callback pseudo type.
Use it with call_user_func or call_user_func_array
The manual gives great examples of usage for the above.
Also see the new php 5.4 Closure::bindTO method if you want to be able to easily use the $this keyword in it.
mmmh guys, i really hope my english is good enaught to explain what i need.
Lets take this example (that is just an example!) of code:
class Something(){
public function Lower($string){
return strtolower($string);
}
}
class Foo{
public $something;
public $reg;
public $string;
public function __construct($reg, $string, $something){
$this->something = $something;
$this->reg = $reg;
$this->string = $string;
}
public function Replace(){
return preg_replace_callback($this->reg, 'Foo::Bar', $this->string);
}
public static function Bar($matches){
/*
* [...]
* do something with $matches and create the $output variable
* [...]
*/
/*
* I know is really useless in this example, but i need to have an istance to an object here
* (in this example, the Something object, but can be something else!)
*/
return $this->something->Lower($output);
}
}
$s = new Something();
$foo = new Foo($myregexp, $mystring, $s);
$content = $foo->Replace();
So, the php manual say that to use a class method as callback in preg_replace_callback(), the method must be abstract.
I need to pass an instance of a previuosly initialized object (in the example, an instance of the Something class) at the callback function.
I tryed to use call_user_func(), but doesnt work (becose in this way i miss the matches parameter).
Is there a way to do that, or have i to separate the process (doing before preg_match_all, for each match retrieve the replace value, and then a simple preg_replace)?
edit: as a side-note, before the tom haigh answer, i used this work-around (in the example, this is the Replace method):
$has_dynamic = preg_match_all($this->reg, $this->string, $dynamic);
if($has_dynamic){
/*
* The 'usefull' subset of my regexp is the third, so $dynamic[2]
*/
foreach($dynamic[2] AS $key => $value){
$dynamic['replaces'][$key] = $this->Bar($value);
}
/*
* ..but i need to replace the complete subset, so $dynamic[0]
*/
return str_replace($dynamic[0], $dynamic['replaces'], $this->string);
}else{
return $this->string;
}
Hope can help someone.
It is hard to pass arguments to callbacks, but instead of this:
return preg_replace_callback($this->reg, 'Foo::Bar', $this->string);
You could make Bar() not static, and use this:
return preg_replace_callback($this->reg, array($this, 'Bar'), $this->string);
Then the callback function will be able to see $this
See 'callback' in Pseudo-types and variables
Also in PHP >=5.3 you could use anonymous functions/closures to pass other data to callback functions.
I got stuck while trying to pass an argument (extra parameter) to a callback
with the create_function() and call_user_function() methods.
This is for reference:
<?php
$pattern = "/([MmT][a-z]*)/";
$string = "Mary is a naughty girl because she took all my animals.";
$kill = "Mary";
echo preg_replace_callback($pattern, function($ma) use ($kill) {
foreach ($ma as $m){
if ($m == $kill){
return "Jenny";
}
return "($m)";
}
}, $string);
echo "\n";
?>
$ php preg_replace_callback.php
Jenny is a naughty girl because she took all (my) ani(mals).
yes I use something like this to set and unset a changing variable so that it is available to the callback function and you don't need the newer php to do it:
foreach ($array as $key) {
$this->_current_key = $key;
preg_replace_callback($regex, array($this, '_callback'), $content);
unset($this->_current_key);
}
then in the callback function $this->_current_key is available:
function _callback ($match) {
//use the key to do something
new_array[$key] = $match[0];
//and still remove found string
return '';
}
How would I do something like this :
class Test
{
public function test($methodName) {
$this->$methodName;
}
private function a() {
echo("a");
}
private function b() {
echo("b");
}
}
$testObj = new Test();
$testObj->test("a()");
$testObj->test("b()");
Maybe I should just pass a parameter "TYPE" and use a "IF statement" but I'm just curious! :)
And what if the "dynamic function name" has one or more parameters?
UPDATE : Thanks everyone! :)
UPDATE #2 - Answer :
class Test
{
public function testOut($methodName) {
$this->$methodName();
}
private function a() {
echo("a");
}
private function b() {
echo("b");
}
}
$testObj = new Test();
$testObj->testOut("a");
$testObj->testOut("b");
The problem with the class is that there was a method named "Test" (the same as the class name)... I changed it and it worked.
class Test
{
public function test($methodName) {
$this->$methodName();
}
private function a() {
echo("a");
}
private function b() {
echo("b");
}
}
$testObj = new Test();
$testObj->test("a");
$testObj->test("b");
Check out call_user_func() - it should do what you want.
Documentation here
call_user_func allows you to do things like this.
For example,
funcname = 'a';
call_user_func(array($testObj, $funcname));
The other alternative is to use variable methods
For example,
$funcname = 'a';
$testObj->$funcname();
If you have a "dynamic function name" with more than one parameter, you can use call_user_func_array, like this:
//in class context..
//$parameters can be an array like array(1,2)
call_user_func_array(array($this, $methodName), $parameters);
The reason you would want to use call_user_func_array instead of call_user_func is that you can pass the parameters the function takes as an array, instead of just as additional parameters, thus allowing you to easily have a variable number of arguments.
Following your particular example and use case, the only way to achieve this exactly:
$testObj = new Test();
$testObj->test("a()");
$testObj->test("b()");
would be to use eval():
class Test
{
public function test($methodName) {
eval($methodName);
}
private function a() {
echo("a");
}
private function b() {
echo("b");
}
}
$testObj = new Test();
$testObj->test("a()");
$testObj->test("b()");
Others pointed out a solution using call_user_func() and rightly so. Also evidently, is faster than using eval() for function calls. Read this:
http://nz.php.net/manual/en/function.call-user-func.php#64415