Pass a function by reference in PHP - php

Is it possible to pass functions by reference?
Something like this:
function call($func){
$func();
}
function test(){
echo "hello world!";
}
call(test);
I know that you could do 'test', but I don't really want that, as I need to pass the function by reference.
Is the only way to do so via anonymous functions?
Clarification: If you recall from C++, you could pass a function via pointers:
void call(void (*func)(void)){
func();
}
Or in Python:
def call(func):
func()
That's what i'm trying to accomplish.

For what it's worth, how about giving something like this a shot? (Yes, I know it's an anonymous function which was mentioned in the post, but I was disgruntled at the abundance of replies that did not mention closures/function-objects at all so this is mostly a note for people running across this post.)
I don't use PHP, but using a closure appears to work in PHP 5.3 (but not PHP 5.2) as demonstrated here. I am not sure what the limitations, if any, there are. (For all I know the closure will eat your children. You have been warned.)
function doIt ($fn) {
echo "doIt\n";
return $fn();
}
function doMe () {
echo "doMe\n";
}
// I am using a closure here.
// There may be a more clever way to "get the function-object" representing a given
// named function, but I do not know what it is. Again, I *don't use PHP* :-)
echo doIt(function () { doMe(); });
Happy coding.

The problem with call_user_func() is that you're passing the return value of the function called, not the function itself.
I've run into this problem before too and here's the solution I came up with.
function funcRef($func){
return create_function('', "return call_user_func_array('{$func}', func_get_args());");
}
function foo($a, $b, $c){
return sprintf("A:%s B:%s C:%s", $a, $b, $c);
}
$b = funcRef("foo");
echo $b("hello", "world", 123);
//=> A:hello B:world C:123
ideone.com demo

No, functions are not first class values in PHP, they cannot be passed by their name literal (which is what you're asking for). Even anonymous functions or functions created via create_function are passed by an object or string reference.
You can pass a name of a function as string, the name of an object method as (object, string) array or an anonymous function as object. None of these pass pointers or references, they just pass on the name of the function. All of these methods are known as the callback pseudo-type: http://php.net/callback

function func1(){
echo 'echo1 ';
return 'return1';
}
function func2($func){
echo 'echo2 ' . $func();
}
func2('func1');
Result:
echo1 echo2 return1

In PHP 5.4.4 (haven't tested lower or other versions), you can do exactly as you suggested.
Take this as an example:
function test ($func) {
$func('moo');
}
function aFunctionToPass ($str) {
echo $str;
}
test('aFunctionToPass');
The script will echo "moo" as if you called "aFunctionToPass" directly.

A similar pattern of this Javascript first class function:
function add(first, second, callback){
console.log(first+second);
if (callback) callback();
}
function logDone(){
console.log('done');
}
function logDoneAgain(){
console.log('done Again');
}
add(2,3, logDone);
add(3,5, logDoneAgain);
Can be done in PHP (Tested with 5.5.9-1ubuntu on C9 IDE) in the following way:
// first class function
$add = function($first, $second, $callback) {
echo "\n\n". $first+$second . "\n\n";
if ($callback) $callback();
};
function logDone(){
echo "\n\n done \n\n";
}
call_user_func_array($add, array(2, 3, logDone));
call_user_func_array($add, array(3, 6, function(){
echo "\n\n done executing an anonymous function!";
}));
Result: 5 done 9 done executing an anonymous function!
Reference: https://github.com/zenithtekla/unitycloud/commit/873659c46c10c1fe5312f5cde55490490191e168

You can create a reference by assigning the function to a local variable when you declare it:
$test = function() {
echo "hello world!";
};
function call($func){
$func();
}
call($test);

You can say
$fun = 'test';
call($fun);

Instead of call(test);, use call_user_func('test');.

As of PHP 8.1, you can use First-class callables:
call(test(...));
You can even use methods:
call($obj->test(...));
As simple as it is.

It appears a bit unclear why do you want to pass functions by reference? Usually things are passed by reference only when the referenced data needs to be (potentially) modified by the function.
As PHP uses arrays or strings to refer functions, you could just pass an array or a string by reference and that would allow the function reference to be modified.
For example, you could do something like
<?php
$mysort = function($a, b) { return ($a < $b) ? 1 : -1; };
adjust_sort_from_config($mysort); // modifies $mysort
do_something_with_data($mysort);
where
<?php
function load_my_configuration(&$fun)
{
$sort_memory = new ...;
...
$fun = [$sort_memory, "customSort"];
// or simply
$fun = function($a, b) { return (rand(1,10) < 4 ? 1 : -1; };
}
This works because there are three ways to refer to function in PHP via a variable:
$name – the string $name contains the name of the function in global namespace that should be called
array($object, $name) – refers to method called string $name of object $object.
array($class, $name) – refers to static function string $name of class $class.
If I remember correctly, the methods and static functions pointed by these constructs must be public. The "First-class callable syntax" should improve this restriction given recent enough PHP version but it seems to be just some syntactic sugar around Closure::fromCallable().
Anonymous functions work the same behind the scenes. You just don't see the literal random names of those functions anywhere but the reference to an anonymous function is just a value of a variable, too.

Related

Passing a function by reference

Is it possible to pass a function by reference? So everytime the reference variable is called the function will be called aswell. Take a look at my code.
<?php
class Documents {
private static $docs = array(
'She went to the toilet and on her way back, opened the wrong door',
'She had found something that would mean she\'d never be poor again - but there was a catch',
'It was just for one night',
'He watched, helpless, as the door closed behind her'
);
public static function get() {
return self::$docs[array_rand(self::$docs)];
}
}
class Printer {
public static $content;
}
Printer::$content = &Documents::get();
echo Printer::$content;
echo "\n" . Printer::$content;
echo "\n" . Printer::$content;
Right now it'll print 3 similar lines but i would like it to call Documents::get() everytime Printer::$content is printed because Printer::$content = **&**Documents::get(); it is by reference.
No, you cannot have a variable which you treat as a variable which nonetheless runs code behind the scenes. If you write $foo, that's using the value of a variable. Only of you write $foo() are you explicitly executing a function.
Having said that, there are some situations in which object methods will be called implicitly. For instance, if $foo is an object and you use it in a string context:
echo $foo;
This will (try to) implicitly call $foo->__toString().
Please do not get the idea to somehow abuse this implied method call to do anything fancy. If you want to call functions, call functions. You can even return functions from other functions, so there's no lack of possibility to pass around functions. You will have to call them explicitly with () however.
There are variable functions:
php > function foo($bar) { echo $bar; }
php > $baz = 'foo';
php > $baz('qux');
qux
But you cannot have PHP automatically execute that "referenced" function when the variable is simply accessed, e.g:
php > $baz;
php >
As you can see, the foo function was not called, and no output was performed. Without the () to signify a function call, that variable is like any other - it's just a string whose contents happen to be the same as a particular functions. It's the () that makes the string "executable".
Note that variable functions, while useful in some limited circumstances, should be avoided as they can lead to spaghetti code and difficult-to-debug bugs.
You can use the magic method __get().
class Printer {
public function __get($name)
{
switch($name) {
case "content":
return Documents::get();
break;
default:
return $this->$name;
break;
}
}
}
But this cannot be done in static context. So you would have to have an instance of Printer. (Perhaps use a singleton?)

Use of Anonymous Functions in PHP

This question may be silly. But an anonymous function does not really seem that anonymous to me. Maybe I am understanding it wrong, but an anonymous function must be stored in some variable, so it can later be referenced by this variable. If this is the case, what makes the below function so anonymous or so different than a regular function (other than the ability to store the function itself in a variable)? Or to word it differently, how is an anonymous function MORE useful than a regular function?
<?php
$greet = function($name)
{
printf("Hello %s\r\n", $name);
};
function greet($name)
{
printf("Hello %s\r\n", $name);
}
$greet('World');
$greet('PHP');
greet('World');
greet('PHP');
?>
Imagine you want to sort a list of users by username. Instead of defining a named comparison function that you're only going to use once, you can use an anonymous function:
usort($users, function($a, $b) {
return strcmp($a['username'], $b['username']);
});
The function itself has no name, as you show in your example you can still create a "real" function with the "same name". They're usually used like this as callbacks, which may seem more "anonymous":
foo(function ($bar) { ... });
One useful thing about anonymous (or lambda, if you prefer) functions is that they allow for creating your callback function inline with the code that needs it, rather than setting up a global function that will only be used in that one context. For instance:
$foo = native_function($bar, callback_function);
can be instead :
$foo = native_function($bar, function() { return $bar + 1; } );
Another handy thing about anonymous functions is that the variable you set it to calls that function every time, so it's not storing a value, but deriving it instead. This is great if a variable represents some derived value. Example:
$tax = .1;
$total = function() use (&$price, &$tax) { return $price * (1 + $tax); };
$price = 5.00;
echo $total(); // prints 5.50
$price = $price + 1;
echo $total(); // prints 6.60
$discount = $total() - 2;
echo $discount; // prints 4.60;
Instead of having to call a function like get_total and passing it $price every time, you interact with a variable that is always set to the newest value because it derives that value every time with the lambda function.

PHP returning by reference not working with normal functions but working with OOP

If I try this code :
<?php
class ref
{
public $reff = "original ";
public function &get_reff()
{
return $this->reff;
}
public function get_reff2()
{
return $this->reff;
}
}
$thereffc = new ref;
$aa =& $thereffc->get_reff();
echo $aa;
$aa = " the changed value ";
echo $thereffc->get_reff(); // says "the changed value "
echo $thereffc->reff; // same thing
?>
Then returning by reference works and the value of the object property $reff gets changed as the variable $aa that references it changes too.
However, when I try this on a normal function that is not inside a class, it won't work !!
I tried this code :
<?php
function &foo()
{
$param = " the first <br>";
return $param;
}
$a = & foo();
$a = " the second <br>";
echo foo(); // just says "the first" !!!
it looks like the function foo() wont recognize it returns by reference and stubbornly returns what it wants !!!
Does returning by reference work only in OOP context ??
That is because a function's scope collapses when the function call completes and the function local reference to the variable is unset. Any subsequent calls to the function create a new $param variable.
Even if that where not the case in the function you are reassigning the variable to the first <br> with each invocation of the function.
If you want proof that the return by reference works use the static keyword to give the function variable a persistent state.
See this example
function &test(){
static $param = "Hello\n";
return $param;
}
$a = &test();
echo $a;
$a = "Goodbye\n";
echo test();
Echo's
Hello
Goodbye
Does returning by reference work only in OOP context ??
No. PHP makes no difference if that is a function or a class method, returning by reference always works.
That you ask indicates you might have not have understood fully what references in PHP are, which - as we all know - can happen. I suggest you read the whole topic in the PHP manual and at least two more sources by different authors. It's a complicated topic.
In your example, take care which reference you return here btw. You set $param to that value - always - when you call the function, so the function returns a reference to that newly set variable.
So this is more a question of variable scope you ask here:
Variable scope

Use contents of string variable to call function

I have the following piece of code
copy($source, $target);
I also use
move_uploaded_file($source, $target);
To prevent code reuse, I want to pass copy and move_uploaded_file in via a variable.
If my variable is $var = "copy";, simply putting $var($source, $target);, doesn't seem to work.
Are there any special characters that must surround $var?
Thanks.
The correct syntax is $var (variable functions), so your code should work.
But please don't do that, just write the code in a straightforward and readable manner. There are legitimate use cases for this technique, but this is not one of them.
You want to look at Variable Functions which goes on to explain how to do that.
function foo() {
echo "In foo()<br />\n";
}
$bar = 'foo';
$bar(); //this calls foo()
This can also be done on both object methods and static methods.
Object Methods
class Foo
{
function MyFunction()
{
//code here
}
}
$foo = new Foo();
$funcName = "MyFunction";
$foo->$funcName();
Static Methods
class Bar
{
static function MyStaticFunction()
{
//code here
}
}
$funcName = "MyStaticFunction";
Bar::$funcName();
While maybe not the case in your situation, when dealing with functions dynamically like this, it is important to check whether the function actually exists and/or is callable.
Alternatively to using Variable Functions, you can use call_user_func which will call the function based on the string name and with provided parameters.
You can use the PHP function call_user_func().
More info here.
You can use call_user_func to do this.
$result = call_user_func($functionToCall, $source, $target)
Documentation: PHP: call_user_func
as far as i know your code should work
here is the link for your refrence

What is the main difference between the following statements?

Recently i was studying the "Passing by Reference", I come to know following ways
What is the main difference between the following methods.
1.
function foo(&$var)
{
$var++;
}
$a=5;
foo($a);
2.
function foo($var)
{
$var++;
}
$a=5;
foo(&$a);
3.
function foo(&$var)
{
$var++;
}
function &bar()
{
$a = 5;
return $a;
}
foo(bar());
even though all of them produce same results, and which is the best way to work with.
Thanks.
function foo(&$var)
{
$var++;
}
$a=5;
foo($a);
This accepts a parameter that is always passed by reference (the & is in foo(&$var)). When $a is passed, it's always as a reference, so incrementing the variable inside the function will cause the parameter to be modified.
function foo($var)
{
$var++;
}
$a=5;
foo(&$a);
Do not use this. This is call-time pass-by-reference (you're passing &$a, a reference to $a, into the function), and is deprecated as of PHP 5.3.0. It's bad practice because the function doesn't expect a reference.
function foo(&$var)
{
$var++;
}
function &bar()
{
$a = 5;
return $a;
}
foo(bar());
This returns a reference (the & is in &bar()) to a variable $a declared in the function bar(). It then takes a reference to the return value of bar() and increments it. I'm not sure at a glance why this would be useful, though, especially for primitive/scalar types.
The second method is deprecated and should never be used.
Typically the function should just return the value.
function foo($a)
{
$a = 5;
}
$a = foo($a);
That's basically what the third method is doing. Not sure why you included an embedded pass by reference.
Pass by reference (for scalars and arrays) should generally be avoided because it's less clear than returning the value. However, it can be useful in cases where you need to modify multiple values within one function call.
Note that in PHP5, there's not even a need to explicitly pass an object by reference if you simply want to modify the original object, as the handle to the object will point to the same object as was passed to the function.
The last example is not equivalent to the first two. If you print the value of $a after calling foo, you will see that it is not defined. The third is basically an obfuscated no-op.

Categories