Pass by reference, with a variable numbers of parameters in PHP? - php

I have a function that takes a variable number of parameters, and I have to pass them by reference to another function.
Such as
function my_function($arg0, $arg1, $arg2, ...)
{
my_other_function(&$arg0, &$arg1, &$arg2, ...);
}
So that when I pass things by reference to my_function, my_other_function also gets them by reference.
Is there a way to do this?

I wonder why you need this. In general references are bad in PHP.
If you really want to do this the only proper way (ignoring call-time pass-by-ref hacks, which won't work with PHP 5.4 anymore anyways) is to use an array wrapping the parameters:
function myfunc(array $data) {
$data[0] += 42;
/* ... */
}
$var = 0;
myfunc(array(&$var /*, ... */));
echo $var; // prints 42
For passing to the other function you can then use call_user_func_array()

Technically you are not doing this:
function my_function($arg0, $arg1, $arg2, ...)
{
my_other_function(&$arg0, &$arg1, &$arg2, ...);
}
but this:
function my_function(&$arg0, &$arg1, &$arg2, ...)
{
my_other_function($arg0, $arg1, $arg2, ...);
}
However as #johannes already wrote, there is no good support for variable number of arguments that are references in PHP (and who could know better). func_get_argsDocs for example does not work with references.
Instead make use of the suggestion to pass all references via an array parameter. That works.
function my_function(array $args)
{
my_other_function($args);
}

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

Passing function as an argument of another function in PHP

I want to pass function (not the result) as an argument of another function. Let's say I have
function double_fn($fn)
and i want to run given function ($fn) two times. Is there such mechanism in PHP? I know you in python function is a kind of variable but is PHP similar?
#edit
is there similar way to use methods?
function double_fn(parrot::sing())
Since 5.3 (note) you do this with closures quite naturally:
function double_fn(callable $fn)
{
$fn();
$fn();
}
double_fn(function() {
echo "hi";
});
(note) type hint only since 5.4
The callable type can be a few things:
a string comprising the function name to call,
a closure (as above)
an array comprising class (or instance) and method to call
Examples of the above is explained in the manual.
Update
edit is there similar way to use methods?
function double_fn(parrot::sing())
Doing that will pass the result of parrot::sing() into the function; to pass a "reference" to the static method you would need to use either:
double_fn('parrot::sing');
double_fn(['parrot', 'sing']);
It's... a bit different. Pass the function name as a string.
function foo()
{
echo "foobar\n";
}
function double_fn($fn)
{
$fn();
$fn();
}
double_fn('foo');
You can use anonymous functions introduced in PHP 5.3.0:
function double_fn($fn) {
$fn();
}
double_fn(function(){
// fonction body
});
or:
$myFn = function(){
// fonction body
};
double_fn($myFn);

Wrapper method for mysqli_bind_param

I'm writing a Database wrapper class and need something like:
public function bind($types, $params, ...) {
$this->prep->bind_param($types, $params, ...);
}
How can I make the arguments dynamic, to have N-params?
I know of the function func_get_args() but doesn't help, I can fetch the arguments, but how to pass?
Off the top of my head, you could do it using call_user_func_array():
public function bind() {
$args=func_get_args();
$method=array($this->prep,'bind_param');
call_user_func_array($method,$args);
}
The function call_user_func_array should be what you need, something along the lines of the following:
public function bind () {
$args = func_get_args();
call_user_func_array(array($this->prep, "bind_param"), $args);
}
call_user_func and call_user_func_array can sometimes be a little slower than calling a method directly, unfortunately there isn't much you can do about this apart from hard code in the first few arguments.
Use an array, i advise you to use the classic way and keep some "core" arguments away from the array, than you can put optionnal ones in an array like so:
function function(Class $object, array $options = array()){
}

Get number of parameters a function requires

This is an extension question of PHP pass in $this to function outside class
And I believe this is what I'm looking for but it's in python not php: Programmatically determining amount of parameters a function requires - Python
Let's say I have a function like this:
function client_func($cls, $arg){ }
and when I'm ready to call this function I might do something like this in pseudo code:
if function's first parameter equals '$cls', then call client_func(instanceof class, $arg)
else call client_func($arg)
So basically, is there a way to lookahead to a function and see what parameter values are required before calling the function?
I guess this would be like debug_backtrace(), but the other way around.
func_get_args() can only be called from within a function which doesn't help me here.
Any thoughts?
Use Reflection, especially ReflectionFunction in your case.
$fct = new ReflectionFunction('client_func');
echo $fct->getNumberOfRequiredParameters();
As far as I can see you will find getParameters() useful too
Only way is with reflection by going to http://us3.php.net/manual/en/book.reflection.php
class foo {
function bar ($arg1, $arg2) {
// ...
}
}
$method = new ReflectionMethod('foo', 'bar');
$num = $method->getNumberOfParameters();

Passing a function's args straight to another function

In PHP, is there a way to send a function's arguments straight to another function without having to specify them one by one? Is there a way to expand func_get_arg() so that the other function receives the individual arguments and not just a single array?
I'd like to send the arguments from foo() straight to bar() like so:
function foo($arg1, $arg2, $arg3)
{
$args = expand_args(func_get_arg());
bar($args);
}
yes.
function foo($arg1, $arg2, $arg3)
{
$args = func_get_arg();
call_user_func_array("bar",$args);
}
If you want to call it on a function belonging to an instance of an entirely seperate class, that can be done by passing the first arg to call_user_func_array as an array.
In this example, the function foo accepts whatever arguments, and passes them directly into $bar->baz->bob(), and returns the result.
public function foo(/* example arguments */)
{
return call_user_func_array
(
array($bar->baz, 'bob'),
func_get_args()
);
}

Categories