Function chaining with different return values? - php

Is it possible to have a method return different values depending on context (how the return value is used)? For example, could a method return $this when it's then used with the arrow operator to call another method (i.e. chaining method calls), but return a scalar when the return value isn't used this way?
Case 1:
$result = $test->doSomething1(); // returns 4
// $result returns 4
Case 2:
$result = $test->doSomething1()->doSomething2();
// doSomething1() returns $this
// doSomething2() returns 8
Is there anyway to perform such a behaviour?

If I understand the question correctly, you want a method (doSomething1) to return a value based on what the rest of the call chain looks like. Unfortunately, there is absolutely no way you can do this.
Common programming paradigms shared across "all" languages (how methods, operators and such work in the context of the grammar) dictate that the result of the expression $this->doSomething1() has to be worked out before the result of possibly calling ->doSomething2() on it can be considered. Statically typed and dynamically typed languages do this in different ways, but the common factor is that the expression $this->doSomething1() has to be considered independently of what follows or does not follow.
In a nutshell: $this->doSomething1() has to return a specific type of value in both cases. And in PHP there is no way to have a type of value that can behave like a number in one context and like an object with methods to call in another.

No it's not possible to have a function return different values depending on if another function is called on the returned value or not. You can emulate this with toString() (where conversion to string is applicable, or another function that you call at the end of every chain to get the value instead of the object:
$test = new foo();
echo $test->doSomething1(); // Outputs 1
$test = new foo();
echo $test->doSomething1()->doSomething2(); // Outputs 3
$test = new foo();
$result = $test->doSomething1()->done(); // $result === 1
$test = new foo();
$result = $test->doSomething1()->doSomething2()->done(); // $result === 3
class foo {
private $val;
function __construct($val = 0){
$this->val = $val;
}
function doSomething1(){
$this->val += 1;
return $this;
}
function doSomething2(){
$this->val += 2;
return $this;
}
function done(){
return $this->val;
}
function __toString(){
return (string)$this->val;
}
}
Codepad Example

This answer suggests creating an internal call stack on the class, so you can keep track of where you are on the method chain. This could be used to return $this or something else, depending on the context.

Related

How to store a name of a function in an array and call it when needed? [duplicate]

I need to be able to call a function, but the function name is stored in a variable, is this possible? e.g:
function foo ()
{
//code here
}
function bar ()
{
//code here
}
$functionName = "foo";
// I need to call the function based on what is $functionName
$functionName() or call_user_func($functionName)
My favorite version is the inline version:
${"variableName"} = 12;
$className->{"propertyName"};
$className->{"methodName"}();
StaticClass::${"propertyName"};
StaticClass::{"methodName"}();
You can place variables or expressions inside the brackets too!
Solution: Use PHP7
Note: For a summarized version, see TL;DR at the end of the answer.
Old Methods
Update: One of the old methods explained here has been removed. Refer to other answers for explanation on other methods, it isn't covered here. By the way, if this answer doesn't help you, you should return upgrading your stuff. PHP 5.6 support has ended in January 2019 (now even PHP 7.2 and 7.3 are not being supported). See supported versions for more information.
As others mentioned, in PHP5 (and also in newer versions like PHP7) we could use variables as function names, use call_user_func() and call_user_func_array(), etc.
New Methods
As of PHP7, there are new ways introduced:
Note: Everything inside <something> brackets means one or more expressions to form something, e.g. <function_name> means expressions forming a function name.
Dynamic Function Call: Function Name On-the-fly
We can form a function name inside parentheses in just one go:
(<function_name>)(arguments);
For example:
function something(): string
{
return "something";
}
$bar = "some_thing";
(str_replace("_", "", $bar))(); // something
// Possible, too; but generally, not recommended, because makes your
// code more complicated
(str_replace("_", "", $bar))()();
Note: Although removing the parentheses around str_replace() is not an error, putting parentheses makes code more readable. However, you cannot do that sometimes, e.g. while using . operator. To be consistent, I recommend you to put the parentheses always.
Dynamic Function Call: Callable Property
A useful example would be in the context of objects: If you have stored a callable in a property, you have to call it this way:
($object->{<property_name>})();
As a simple example:
// Suppose we're in a class method context
($this->eventHandler)();
Obviously, calling it as $this->eventHandler() is plain wrong: By that you mean calling a method named eventHandler.
Dynamic Method Call: Method Name On-the-fly
Just like dynamic function calls, we can do the same way with method calls, surrounded by curly braces instead of parentheses (for extra forms, navigate to TL;DR section):
$object->{<method_name>}(arguments);
$object::{<method_name>}(arguments);
See it in an example:
class Foo
{
public function another(): string
{
return "something";
}
}
$bar = "another thing";
(new Something())->{explode(" ", $bar)[0]}(); // something
Dynamic Method Call: The Array Syntax
A more elegant way added in PHP7 is the following:
[<object>, <method_name>](arguments);
[<class_name>, <method_name>](arguments); // Static calls only
As an example:
class Foo
{
public function nonStaticCall()
{
echo "Non-static call";
}
public static function staticCall()
{
echo "Static call";
}
}
$x = new X();
[$x, "non" . "StaticCall"](); // Non-static call
[$x, "static" . "Call"](); // Static call
Note: The benefit of using this method over the previous one is that, you don't care about the call type (i.e. whether it's static or not).
Note: If you care about performance (and micro-optimizations), don't use this method. As I tested, this method is really slower than other methods (more than 10 times).
Extra Example: Using Anonymous Classes
Making things a bit complicated, you could use a combination of anonymous classes and the features above:
$bar = "SomeThing";
echo (new class {
public function something()
{
return 512;
}
})->{strtolower($bar)}(); // 512
TL;DR (Conclusion)
Generally, in PHP7, using the following forms are all possible:
// Everything inside `<something>` brackets means one or more expressions
// to form something
// Dynamic function call via function name
(<function_name>)(arguments);
// Dynamic function call on a callable property
($object->{<property_name>})(arguments);
// Dynamic method call on an object
$object->{<method_name>}(arguments);
$object::{<method_name>}(arguments);
// Dynamic method call on a dynamically-generated object
(<object>)->{<method_name>}(arguments);
(<object>)::{<method_name>}(arguments);
// Dynamic method call, statically
ClassName::{<method_name>}(arguments);
(<class_name>)::{<method_name>}(arguments);
// Dynamic method call, array-like (no different between static
// and non-static calls
[<object>, <method_name>](arguments);
// Dynamic method call, array-like, statically
[<class_name>, <method_name>](arguments);
Special thanks to this PHP talk.
Yes, it is possible:
function foo($msg) {
echo $msg."<br />";
}
$var1 = "foo";
$var1("testing 1,2,3");
Source: http://www.onlamp.com/pub/a/php/2001/05/17/php_foundations.html?page=2
As already mentioned, there are a few ways to achieve this with possibly the safest method being call_user_func() or if you must you can also go down the route of $function_name(). It is possible to pass arguments using both of these methods as so
$function_name = 'foobar';
$function_name(arg1, arg2);
call_user_func_array($function_name, array(arg1, arg2));
If the function you are calling belongs to an object you can still use either of these
$object->$function_name(arg1, arg2);
call_user_func_array(array($object, $function_name), array(arg1, arg2));
However if you are going to use the $function_name() method it may be a good idea to test for the existence of the function if the name is in any way dynamic
if(method_exists($object, $function_name))
{
$object->$function_name(arg1, arg2);
}
A few years late, but this is the best manner now imho:
$x = (new ReflectionFunction("foo"))->getClosure();
$x();
In case someone else is brought here by google because they were trying to use a variable for a method within a class, the below is a code sample which will actually work. None of the above worked for my situation. The key difference is the & in the declaration of $c = & new... and &$c being passed in call_user_func.
My specific case is when implementing someone's code having to do with colors and two member methods lighten() and darken() from the csscolor.php class. For whatever reason, I wanted to have the same code be able to call lighten or darken rather than select it out with logic. This may be the result of my stubbornness to not just use if-else or to change the code calling this method.
$lightdark="lighten"; // or optionally can be darken
$color="fcc"; // a hex color
$percent=0.15;
include_once("csscolor.php");
$c = & new CSS_Color($color);
$rtn=call_user_func( array(&$c,$lightdark),$color,$percent);
Note that trying anything with $c->{...} didn't work. Upon perusing the reader-contributed content at the bottom of php.net's page on call_user_func, I was able to piece together the above. Also, note that $params as an array didn't work for me:
// This doesn't work:
$params=Array($color,$percent);
$rtn=call_user_func( array(&$c,$lightdark),$params);
This above attempt would give a warning about the method expecting a 2nd argument (percent).
For the sake of completeness, you can also use eval():
$functionName = "foo()";
eval($functionName);
However, call_user_func() is the proper way.
Dynamic function names and namespaces
Just to add a point about dynamic function names when using namespaces.
If you're using namespaces, the following won't work except if your function is in the global namespace:
namespace greetings;
function hello()
{
// do something
}
$myvar = "hello";
$myvar(); // interpreted as "\hello();"
What to do?
You have to use call_user_func() instead:
// if hello() is in the current namespace
call_user_func(__NAMESPACE__.'\\'.$myvar);
// if hello() is in another namespace
call_user_func('mynamespace\\'.$myvar);
Complementing the answer of #Chris K if you want to call an object's method, you can call it using a single variable with the help of a closure:
function get_method($object, $method){
return function() use($object, $method){
$args = func_get_args();
return call_user_func_array(array($object, $method), $args);
};
}
class test{
function echo_this($text){
echo $text;
}
}
$test = new test();
$echo = get_method($test, 'echo_this');
$echo('Hello'); //Output is "Hello"
I posted another example here
Use the call_user_func function.
What I learnt from this question and the answers. Thanks all!
Let say I have these variables and functions:
$functionName1 = "sayHello";
$functionName2 = "sayHelloTo";
$functionName3 = "saySomethingTo";
$friend = "John";
$datas = array(
"something"=>"how are you?",
"to"=>"Sarah"
);
function sayHello()
{
echo "Hello!";
}
function sayHelloTo($to)
{
echo "Dear $to, hello!";
}
function saySomethingTo($something, $to)
{
echo "Dear $to, $something";
}
To call function without arguments
// Calling sayHello()
call_user_func($functionName1);
Hello!
To call function with 1 argument
// Calling sayHelloTo("John")
call_user_func($functionName2, $friend);
Dear John, hello!
To call function with 1 or more arguments
This will be useful if you are dynamically calling your functions and each function have different number of arguments. This is my case that I have been looking for (and solved). call_user_func_array is the key
// You can add your arguments
// 1. statically by hard-code,
$arguments[0] = "how are you?"; // my $something
$arguments[1] = "Sarah"; // my $to
// 2. OR dynamically using foreach
$arguments = NULL;
foreach($datas as $data)
{
$arguments[] = $data;
}
// Calling saySomethingTo("how are you?", "Sarah")
call_user_func_array($functionName3, $arguments);
Dear Sarah, how are you?
Yay bye!
If you were in a object context trying to call a function dynamically please try something like this code bellow:
$this->{$variable}();
Following code can help to write dynamic function in PHP.
now the function name can be dynamically change by variable '$current_page'.
$current_page = 'home_page';
$function = #${$current_page . '_page_versions'};
$function = function() {
echo 'current page';
};
$function();
The easiest way to call a function safely using the name stored in a variable is,
//I want to call method deploy that is stored in functionname
$functionname = 'deploy';
$retVal = {$functionname}('parameters');
I have used like below to create migration tables in Laravel dynamically,
foreach(App\Test::$columns as $name => $column){
$table->{$column[0]}($name);
}
Considering some of the excellent answers given here, sometimes you need to be precise.
For example.
if a function has a return value eg (boolean,array,string,int,float
e.t.c).
if the function has no return value check
if the function exists
Let's look at its credit to some of the answers given.
Class Cars{
function carMake(){
return 'Toyota';
}
function carMakeYear(){
return 2020;
}
function estimatedPriceInDollar{
return 1500.89;
}
function colorList(){
return array("Black","Gold","Silver","Blue");
}
function carUsage(){
return array("Private","Commercial","Government");
}
function getCar(){
echo "Toyota Venza 2020 model private estimated price is 1500 USD";
}
}
We want to check if method exists and call it dynamically.
$method = "color List";
$class = new Cars();
//If the function have return value;
$arrayColor = method_exists($class, str_replace(' ', "", $method)) ? call_user_func(array($this, $obj)) : [];
//If the function have no return value e.g echo,die,print e.t.c
$method = "get Car";
if(method_exists($class, str_replace(' ', "", $method))){
call_user_func(array($class, $method))
}
Thanks
One unconventional approach, that came to my mind is, unless you are generating the whole code through some super ultra autonomous AI which writes itself, there are high chances that the functions which you want to "dynamically" call, are already defined in your code base. So why not just check for the string and do the infamous ifelse dance to summon the ...you get my point.
eg.
if($functionName == 'foo'){
foo();
} else if($functionName == 'bar'){
bar();
}
Even switch-case can be used if you don't like the bland taste of ifelse ladder.
I understand that there are cases where the "dynamically calling the function" would be an absolute necessity (Like some recursive logic which modifies itself). But most of the everyday trivial use-cases can just be dodged.
It weeds out a lot of uncertainty from your application, while giving you a chance to execute a fallback function if the string doesn't match any of the available functions' definition. IMHO.
I dont know why u have to use that, doesnt sound so good to me at all, but if there are only a small amount of functions, you could use a if/elseif construct.
I dont know if a direct solution is possible.
something like
$foo = "bar";
$test = "foo";
echo $$test;
should return bar, you can try around but i dont think this will work for functions

Multiple return from a class function

I am learning php OOP. While writing a class I am getting a logical problem that the function is not returning more than one value and I am just getting default value as output.
When I pass two variables in a function setproperty() and call back getproperty(), it returns only author's name. Here is the code:
class library{
public $BookName="PHP OOP Programming";
public $author="Faisal";
public function setproperty($a_name,$b_name){
$this->author=$a_name;
//$this->BookName=$b_name;
}
public function getproperty(){
return $this->author."<br />";
//return $this->BookName."<br />";
}
}
$obj=new library;
//var_dump($obj);
echo $obj->getproperty();
$obj->setproperty("naseer","SQL");
echo $obj->getproperty();
And I'm getting the output:
Faisal
naseer
Whereas the output I wanted is author's name along with books, much like:
Faisal
PHP OOP Programming
naseer
SQL
You cannot return multiple times in a function.
If you need to return more than one value you can do something like:
return array('author'=>$this->author, 'bookName'=>$this->bookName);
And use it like this:
$res = $obj->getproperty();
echo "Author is ".$res['author'];
echo "Book is ".$res['bookName'];
You may want to change this depending on what the method is for/ how it will be used.
A return statement is the end of any function. That's why a function is said "to have returned" when it's done doing whatever it needs to do. This isn't unique to OO, but to functions in all programming languages.
What you want to do is:
return $this->author.'<br/>'.$this->bookName.'<br/>';
Here, I'm concatenating all values into one string constant, and return that. This way, I have a single return value, and a single return statement with the desired output.
Like I said, even non-methods (regular functions) can't return more than 1 value - nor can they return less than 1 value:
function aFunction()
{
echo '123';
}
Though lacking an explicit return:
$foo = 'not null';
$foo = aFunction();
var_dump($foo);//null!
the function clearly does return null, just like in C, a function that needn't return any value, returns void, or a JavaScript function returns undefined. The same applies to methods: they return null, implicitly or a single explicit return value.
You could write code like this, too:
function sillyFunction($someArgument = 1)
{
return true;
if ($someArgument < 0)
{
return false;
}
if ($someArgument === 0)
{
return null;
}
return $someArgument%2;
}
This function starts with a return true; statement. Any code that follows will never be reached, and thus never get executed, because this function has to return something to the caller, who then takes over again. You can't go back to the function and continue what you were doing there. A function is a one-go thing.
Workarounds: Thankfully, objects and arrays are regarded as a single value, so they can be returned from a function, and can contain multiple values. So that's the most common way to somehow get a function to return multiple values. The only, minor downside is that, once the function has returned, you have but a single access point for all these values: the variable to which you assigned the return value:
function foo()
{
return array('foo' => range(1,100), 'bar' => range('A','Z'));
}
$foo = foo();
echo $foo['foo'][1], ' => ', $foo['bar'][1];//echoes 2 => B
In some really rare cases (in the past 10 years, I've needed this ~5 times) you can sort-of return several values using references:
function changeArrayAndReturn(array &$arrayRef)
{
array_push($arrayRef, 'I was added in the function');//alters array
return count($arrayRef);//AND returns int
}
$foo = array();
echo changeArrayAndReturn($foo);//echoes 1
$foo[] = 'I was added outside of the function';
echo changeArrayAndReturn($foo);//echoes 3
var_dump($foo);
//array(I was added in the function, I was added outside of the function, I was added in the function)
But that's dangerous and hard to maintain, so stay away, unless you really can't do it any other way
A function stops when it encounters the first return. So it never gets to the line you commented out (even when it is not a comment).
public function getproperty()
{
return $this->author."<br />".$this->BookName."<br />";
}
That way you display both values with a single return. You could also return an array if you preferred.

Is there a way to check what type of a value a method returns?

I am writing a method which can call any method from any class (this process is dynamic).
In my method, I need to find out what type is the returned value, based on the returned value type,I will proceed on to the next step.
For example:
<?php
function identifyReturnType($className, $methodName) {
$result = $className->$methodName();
//Here I need to find out the $result type
}
?>
I have many classes where methods return bool, string, int etc.
and there are a few methods which do not return anything, those methods set the values in object or the object has resource pointer :
<?php
function getCategories() {
$this->query("SELECT * FROM categories");
}
function getItems() {
$this->query("SELECT * FROM items");
$this->getValues();
}
?>
PHP gettype($var) method finds out what is the value type but for this, my method must return a value. I have cases (as I explained above) where method just sets the query object.
Please share your ideas.
Thank you so much.
This really depends on your implementation. Some follow architecture where every function will return data as array. Even for query returned data is returned in small chunks of array. That is completely on how you optimize or write your script. Say you are getting all contacts and if you have say 10,000 contacts in DB and you return all in an array, thats a bad idea. Rather use pagination and return in small numbers if you want the function to return data as array.
I have had this issue, where we have a big web application written in PHP/Mysql. Over the time we have thousands of functions across different classes. Now we have to develop a REST API which will have different functionality. The main problem was we do not have used different functions to return query object, some to return array, some to return Boolean and so on. The API should return data as JSON. Now we have to choice use the existing code for different functionality or re-write new code for the API. The 2nd choice is more expensive so we are left with first choice. But the problem as I mentioned is far from over the methods will return different type and do we need to really write more codes to check which function is called and if the say function "xyz()" is called and we know its returning query object then loop through it generate array and then json. No thats a bad idea and will take a lot of effort and its better to write seperate code then.
So we follow the following approach.
Our api call looks like
www.api.oursite.com/api/v1/Resource/Method?param=....
Now we catch the Resource and Method where resource is a Class name and Method is a method name for that Class.
so we know we have to call Resource->Method()
Now we have a class called ResourceMethodMap.class.php and it contains the array as
static $resource_method_map = array(
"Users"=>array(
"getUserInfo"=> // gets the user info
array(
"return"=>"array",
"accessToken"=>true
)
),
....
...
)
So the API request processing code does something like
public function call_method($resource = "",$method=""){
if($resource == "") $resource = $this->get_resource();
if($method == "") $method = $this->get_api_method();
if (class_exists($resource)) {
$resource_obj = new $resource();
// Parse the method params as array
$param_array = $this->parse_method_params($resource,$method);
if(false !== $param_array){
$result = call_user_func_array(array($resource_obj, $method), $param_array);
}else{
$result = $resource_obj->$method() ;
}
return $this->process_return_data($resource,$method,$result,$resource_obj);
}else{
$this->setMessage("Invalid Resource");
return false ;
}
}
Here the function process_return_data() will do the returned data conversion as
function process_return_data($resource,$method,$ret_val,$resource_obj = NULL){
if(array_key_exists("return",ResourceMethodMap::$resource_method_map[$resource][$method])){
$return_type = ResourceMethodMap::$resource_method_map[$resource][$method]["return"];
$return_array= array();
switch($return_type){
case 'boolean':
if(false === $ret_val){
return false ;
}else{
if(is_array($ret_val)){
return $ret_val ;
}elseif(true === $ret_val){
return $ret_val ;
}else{
$return_array[] = $ret_val ;
return $return_array ;
}
}
break;
case 'array':
return $ret_val ;
break;
}
.....
}
}
So Yes it completely on the developer how they want their data to be returned. The above example is just one real time scenario how we have implemented.
I have posted the complete code her http://codepad.org/MPY1gVed have look
If i understood your question right you can do this by passing in an argument as a reference.
Here's an example i made for you, if it is any help.
http://php.net/manual/en/language.references.pass.php
Another solution can be to return an array with both the return value and the type.
Do you real need a method to call other methods? You could just instantiate the class and call it manually
In adittion i would recommend checking like so:
if(is_callable($className, $methodName)){
$className->$methodName();
}

Method chaining without final method

I came across plenty of examples of method chaining in PHP, but couldn't find anything about this one, so I'm asking for help you guys;)
My problem is - can I in some way find out if the method in chain is the last one? In most cases people are using some sort of final method (execute, send,..) to tell when the chain ends and return the corresponding result. But I wonder if there is some hidden magic method or technique than can check all the methods in chain and detect if there is no next method?
Without final method it works fine for strings (in the very simple example), but not if I want to return array.
Here is my snippet :
class Chain {
private $strArray;
function __call($name, $args) {
$this->strArray[] = $args[0];
return $this;
}
function __toString() {
return implode('-', $this->strArray);
}
}
// example 1
$c = new Chain();
$x = $c->foo('hi')->bar('stack'); // need array('hi', 'stack')
// example 2
$c = new Chain();
$x = $c->foo('hi')->bar('stack')->foobar('overflow'); // need array('hi', 'stack', 'overflow')
// example 3
$c = new Chain();
echo $c->foo('hi')->foobar('overflow'); // prints 'hi-overflow'
// example 4
$c = new Chain();
echo $c->foo('hi')->bar('stack')->foobar('overflow'); // prints 'hi-stack-overflow'
You see, when I want to print the result of chain, I can modify the result in the __toString method, but what if I need an array (example 1, 2)? Is there any way to achieve that without calling some additional "final" method?
Thanks a lot for help and let me know if you need more info.
EDIT: After feedback from #bandi I tried to extend ArrayObject like this.
class Chain extends ArrayObject {
function __call($name, $args) {
$this->append($args[0]);
return $this;
}
function __toString() {
return implode('-', $this->getIterator()->getArrayCopy());
}
}
// returned ref. to object, works fine in loop or accessing offset
$obj = new Chain;
$x = $obj->foo('hi')->bar('stack')->foobar('overflow'); // need array('hi', 'stack', 'overflow')
foreach ($x as $y) {
echo $y, "\n";
}
var_dump($x[0], $x[1], $x[2]);
// returned String
$c = new Chain;
echo $c->foo('hi')->foobar('overflow'); // prints 'hi-overflow'
It does what I wanted, however I don't feel so good about the $this->getIterator()->getArrayCopy() part. Is there some simple way of accessing the array (internally in ["storage":"ArrayObject":private])?
Thanks
Method chaining is using the return value of a function, in this case this is the reference to the object. Predicting the use of a returned value is generally not possible.
You have to tell the called method that you want to do something different. You can use the second argument for this, e.g. you return a different result if the second argument is defined. The other option might be to modify the class so that it behaves like an array except if it is printed.

How to call a function from a string stored in a variable?

I need to be able to call a function, but the function name is stored in a variable, is this possible? e.g:
function foo ()
{
//code here
}
function bar ()
{
//code here
}
$functionName = "foo";
// I need to call the function based on what is $functionName
$functionName() or call_user_func($functionName)
My favorite version is the inline version:
${"variableName"} = 12;
$className->{"propertyName"};
$className->{"methodName"}();
StaticClass::${"propertyName"};
StaticClass::{"methodName"}();
You can place variables or expressions inside the brackets too!
Solution: Use PHP7
Note: For a summarized version, see TL;DR at the end of the answer.
Old Methods
Update: One of the old methods explained here has been removed. Refer to other answers for explanation on other methods, it isn't covered here. By the way, if this answer doesn't help you, you should return upgrading your stuff. PHP 5.6 support has ended in January 2019 (now even PHP 7.2 and 7.3 are not being supported). See supported versions for more information.
As others mentioned, in PHP5 (and also in newer versions like PHP7) we could use variables as function names, use call_user_func() and call_user_func_array(), etc.
New Methods
As of PHP7, there are new ways introduced:
Note: Everything inside <something> brackets means one or more expressions to form something, e.g. <function_name> means expressions forming a function name.
Dynamic Function Call: Function Name On-the-fly
We can form a function name inside parentheses in just one go:
(<function_name>)(arguments);
For example:
function something(): string
{
return "something";
}
$bar = "some_thing";
(str_replace("_", "", $bar))(); // something
// Possible, too; but generally, not recommended, because makes your
// code more complicated
(str_replace("_", "", $bar))()();
Note: Although removing the parentheses around str_replace() is not an error, putting parentheses makes code more readable. However, you cannot do that sometimes, e.g. while using . operator. To be consistent, I recommend you to put the parentheses always.
Dynamic Function Call: Callable Property
A useful example would be in the context of objects: If you have stored a callable in a property, you have to call it this way:
($object->{<property_name>})();
As a simple example:
// Suppose we're in a class method context
($this->eventHandler)();
Obviously, calling it as $this->eventHandler() is plain wrong: By that you mean calling a method named eventHandler.
Dynamic Method Call: Method Name On-the-fly
Just like dynamic function calls, we can do the same way with method calls, surrounded by curly braces instead of parentheses (for extra forms, navigate to TL;DR section):
$object->{<method_name>}(arguments);
$object::{<method_name>}(arguments);
See it in an example:
class Foo
{
public function another(): string
{
return "something";
}
}
$bar = "another thing";
(new Something())->{explode(" ", $bar)[0]}(); // something
Dynamic Method Call: The Array Syntax
A more elegant way added in PHP7 is the following:
[<object>, <method_name>](arguments);
[<class_name>, <method_name>](arguments); // Static calls only
As an example:
class Foo
{
public function nonStaticCall()
{
echo "Non-static call";
}
public static function staticCall()
{
echo "Static call";
}
}
$x = new X();
[$x, "non" . "StaticCall"](); // Non-static call
[$x, "static" . "Call"](); // Static call
Note: The benefit of using this method over the previous one is that, you don't care about the call type (i.e. whether it's static or not).
Note: If you care about performance (and micro-optimizations), don't use this method. As I tested, this method is really slower than other methods (more than 10 times).
Extra Example: Using Anonymous Classes
Making things a bit complicated, you could use a combination of anonymous classes and the features above:
$bar = "SomeThing";
echo (new class {
public function something()
{
return 512;
}
})->{strtolower($bar)}(); // 512
TL;DR (Conclusion)
Generally, in PHP7, using the following forms are all possible:
// Everything inside `<something>` brackets means one or more expressions
// to form something
// Dynamic function call via function name
(<function_name>)(arguments);
// Dynamic function call on a callable property
($object->{<property_name>})(arguments);
// Dynamic method call on an object
$object->{<method_name>}(arguments);
$object::{<method_name>}(arguments);
// Dynamic method call on a dynamically-generated object
(<object>)->{<method_name>}(arguments);
(<object>)::{<method_name>}(arguments);
// Dynamic method call, statically
ClassName::{<method_name>}(arguments);
(<class_name>)::{<method_name>}(arguments);
// Dynamic method call, array-like (no different between static
// and non-static calls
[<object>, <method_name>](arguments);
// Dynamic method call, array-like, statically
[<class_name>, <method_name>](arguments);
Special thanks to this PHP talk.
Yes, it is possible:
function foo($msg) {
echo $msg."<br />";
}
$var1 = "foo";
$var1("testing 1,2,3");
Source: http://www.onlamp.com/pub/a/php/2001/05/17/php_foundations.html?page=2
As already mentioned, there are a few ways to achieve this with possibly the safest method being call_user_func() or if you must you can also go down the route of $function_name(). It is possible to pass arguments using both of these methods as so
$function_name = 'foobar';
$function_name(arg1, arg2);
call_user_func_array($function_name, array(arg1, arg2));
If the function you are calling belongs to an object you can still use either of these
$object->$function_name(arg1, arg2);
call_user_func_array(array($object, $function_name), array(arg1, arg2));
However if you are going to use the $function_name() method it may be a good idea to test for the existence of the function if the name is in any way dynamic
if(method_exists($object, $function_name))
{
$object->$function_name(arg1, arg2);
}
A few years late, but this is the best manner now imho:
$x = (new ReflectionFunction("foo"))->getClosure();
$x();
In case someone else is brought here by google because they were trying to use a variable for a method within a class, the below is a code sample which will actually work. None of the above worked for my situation. The key difference is the & in the declaration of $c = & new... and &$c being passed in call_user_func.
My specific case is when implementing someone's code having to do with colors and two member methods lighten() and darken() from the csscolor.php class. For whatever reason, I wanted to have the same code be able to call lighten or darken rather than select it out with logic. This may be the result of my stubbornness to not just use if-else or to change the code calling this method.
$lightdark="lighten"; // or optionally can be darken
$color="fcc"; // a hex color
$percent=0.15;
include_once("csscolor.php");
$c = & new CSS_Color($color);
$rtn=call_user_func( array(&$c,$lightdark),$color,$percent);
Note that trying anything with $c->{...} didn't work. Upon perusing the reader-contributed content at the bottom of php.net's page on call_user_func, I was able to piece together the above. Also, note that $params as an array didn't work for me:
// This doesn't work:
$params=Array($color,$percent);
$rtn=call_user_func( array(&$c,$lightdark),$params);
This above attempt would give a warning about the method expecting a 2nd argument (percent).
For the sake of completeness, you can also use eval():
$functionName = "foo()";
eval($functionName);
However, call_user_func() is the proper way.
Dynamic function names and namespaces
Just to add a point about dynamic function names when using namespaces.
If you're using namespaces, the following won't work except if your function is in the global namespace:
namespace greetings;
function hello()
{
// do something
}
$myvar = "hello";
$myvar(); // interpreted as "\hello();"
What to do?
You have to use call_user_func() instead:
// if hello() is in the current namespace
call_user_func(__NAMESPACE__.'\\'.$myvar);
// if hello() is in another namespace
call_user_func('mynamespace\\'.$myvar);
Complementing the answer of #Chris K if you want to call an object's method, you can call it using a single variable with the help of a closure:
function get_method($object, $method){
return function() use($object, $method){
$args = func_get_args();
return call_user_func_array(array($object, $method), $args);
};
}
class test{
function echo_this($text){
echo $text;
}
}
$test = new test();
$echo = get_method($test, 'echo_this');
$echo('Hello'); //Output is "Hello"
I posted another example here
Use the call_user_func function.
What I learnt from this question and the answers. Thanks all!
Let say I have these variables and functions:
$functionName1 = "sayHello";
$functionName2 = "sayHelloTo";
$functionName3 = "saySomethingTo";
$friend = "John";
$datas = array(
"something"=>"how are you?",
"to"=>"Sarah"
);
function sayHello()
{
echo "Hello!";
}
function sayHelloTo($to)
{
echo "Dear $to, hello!";
}
function saySomethingTo($something, $to)
{
echo "Dear $to, $something";
}
To call function without arguments
// Calling sayHello()
call_user_func($functionName1);
Hello!
To call function with 1 argument
// Calling sayHelloTo("John")
call_user_func($functionName2, $friend);
Dear John, hello!
To call function with 1 or more arguments
This will be useful if you are dynamically calling your functions and each function have different number of arguments. This is my case that I have been looking for (and solved). call_user_func_array is the key
// You can add your arguments
// 1. statically by hard-code,
$arguments[0] = "how are you?"; // my $something
$arguments[1] = "Sarah"; // my $to
// 2. OR dynamically using foreach
$arguments = NULL;
foreach($datas as $data)
{
$arguments[] = $data;
}
// Calling saySomethingTo("how are you?", "Sarah")
call_user_func_array($functionName3, $arguments);
Dear Sarah, how are you?
Yay bye!
If you were in a object context trying to call a function dynamically please try something like this code bellow:
$this->{$variable}();
The easiest way to call a function safely using the name stored in a variable is,
//I want to call method deploy that is stored in functionname
$functionname = 'deploy';
$retVal = {$functionname}('parameters');
I have used like below to create migration tables in Laravel dynamically,
foreach(App\Test::$columns as $name => $column){
$table->{$column[0]}($name);
}
Following code can help to write dynamic function in PHP.
now the function name can be dynamically change by variable '$current_page'.
$current_page = 'home_page';
$function = #${$current_page . '_page_versions'};
$function = function() {
echo 'current page';
};
$function();
Considering some of the excellent answers given here, sometimes you need to be precise.
For example.
if a function has a return value eg (boolean,array,string,int,float
e.t.c).
if the function has no return value check
if the function exists
Let's look at its credit to some of the answers given.
Class Cars{
function carMake(){
return 'Toyota';
}
function carMakeYear(){
return 2020;
}
function estimatedPriceInDollar{
return 1500.89;
}
function colorList(){
return array("Black","Gold","Silver","Blue");
}
function carUsage(){
return array("Private","Commercial","Government");
}
function getCar(){
echo "Toyota Venza 2020 model private estimated price is 1500 USD";
}
}
We want to check if method exists and call it dynamically.
$method = "color List";
$class = new Cars();
//If the function have return value;
$arrayColor = method_exists($class, str_replace(' ', "", $method)) ? call_user_func(array($this, $obj)) : [];
//If the function have no return value e.g echo,die,print e.t.c
$method = "get Car";
if(method_exists($class, str_replace(' ', "", $method))){
call_user_func(array($class, $method))
}
Thanks
One unconventional approach, that came to my mind is, unless you are generating the whole code through some super ultra autonomous AI which writes itself, there are high chances that the functions which you want to "dynamically" call, are already defined in your code base. So why not just check for the string and do the infamous ifelse dance to summon the ...you get my point.
eg.
if($functionName == 'foo'){
foo();
} else if($functionName == 'bar'){
bar();
}
Even switch-case can be used if you don't like the bland taste of ifelse ladder.
I understand that there are cases where the "dynamically calling the function" would be an absolute necessity (Like some recursive logic which modifies itself). But most of the everyday trivial use-cases can just be dodged.
It weeds out a lot of uncertainty from your application, while giving you a chance to execute a fallback function if the string doesn't match any of the available functions' definition. IMHO.
I dont know why u have to use that, doesnt sound so good to me at all, but if there are only a small amount of functions, you could use a if/elseif construct.
I dont know if a direct solution is possible.
something like
$foo = "bar";
$test = "foo";
echo $$test;
should return bar, you can try around but i dont think this will work for functions

Categories