Passing a function by reference - php

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?)

Related

Call a variable function using a class property as function name

The following code uses the string "rand" stored in the property $prop to call rand() as a variable function, by using $function as a temporary local variable.
class C
{
private $prop = "rand";
public function execute()
{
$function = $this->prop;
echo $function();
}
}
$c = new C();
$c->execute();
This works, but I need to call the variable function stored in $this->prop using only one statement and avoiding the temporary variable.
I had no luck with
echo $this->prop();
because it actually calls the method prop() which does not exist and in any case it is not what I want to do.
As $this->prop is actually a string, I tried the following, but it produces a syntax error:
echo ($this->prop)();
I also tried
echo call_user_func($this->prop);
Although it does the work, it is not an option for me because it is not a variable function.
It seems like variable functions only work using local variables as function name.
Does anybody know a way to call directly a variable function using a class property as function name, avoiding the local temporary variable and the usage of call_user_func()?
Edit:
I understand your perplexity, therefore I'm going to explain what's wrong with using call_user_func.
I'm just exploring the opportunities offered by variable functions, which seems to be less then those offered by variable variables.
Let's try using variable variables feature it its simplest form.
Suppose we have a function f() which returns the string "something"
function f() {
return "something";
}
then a class property containing the string "something"
$this->prop = "something";
$something is a local variable
$something = "I am a local variable";
Then all the following statements will work:
$r = ${"something"};
$r = ${$this->prop};
$r = ${f()};
My personal conclusion: No matter how the string "something" has been obtained; just surround it with braces {} and prepend a dollar symbol $ to consider it a variable.
Pretty flessibe.
Let's try the same for variable functions
Now we have a function f() which returns the string "rand"
function f() {
return "rand";
}
then a class property containing the string "rand"
$this->prop = "rand";
Variable functions on the other hand, does not allow a string followed by parenthesis () to be considered a function call.
$r = "rand"(); // Produces a syntax error, unexpected '()' after a string
$r = $this->prop(); // Calls the 'prop()' method, which does not exist
$r = f()(); // Again a syntax error, unexpected '()' after the function f()
I have to conclude that variable functions always require a local variable to be run :(
You need to implement a magic __call method, like this:
class C
{
private $prop = "execute";
public function __call($method, $args)
{
if($method == "prop") // just for this prop name
{
if(method_exists($this, $this->prop))
return call_user_func_array([$this, $this->prop], $args);
}
}
public function execute ($s){
echo '>>'.$s.'<<';
}
}
$c = new C;
$c->prop(123);
It certainly does feel like a glaring omission in PHP's syntax. (Although taken literally I guess they are variable functions, not property functions!?) I would have perhaps expected the following "curly brace" syntax to work, but it doesn't, Parse error: syntax error, unexpected '{' in ....
echo {$this->prop}();
However, there are significant benefits to using variable function syntax over other methods. Variable functions are quicker than call_user_func() / call_user_func_array() and natively support pass-by-reference, rather than the "special-case" call-time pass-by-reference with call_user_func_array() (which is deprecated in all other cases).
An alternative to the __call magic method (above), which is going to be relatively slow, is to simply use a wrapper method, to which you pass the function/method name and use variable functions inside that wrapper method.
In its most simplest form:
function callUserFunc($callable) {
return $callable();
}
Because of the performance benefit (over using call_user_func_array()) several frameworks implement a similar "helper" method, allowing for a variable number of arguments. This other question/answer goes into more depth and covers some performance benchmarks: Calling a function with explicit parameters vs. call_user_func_array()
In case anyone is wondering, since PHP 7 we get immedietally invoked function expressions.
While this particular case is undocumented it actually works in the following example:
class Test {
private $func = "strtolower";
public function testFunc() {
return ($this->func)("ALPHABET");
}
}
$t = new Test();
echo $t->testFunc(); //echoes alphabet in PHP 7+ error in anything below
This can be seen in https://3v4l.org/JiuIF

Filter php function return value

Lets say we have function:
function foo() {
return "bar";
}
Is it possible to add some filter to foo() function, for example to make it returning double value like "barbar" without changing the function itself.
So we would have:
foo(); //returns "bar"
function filter($&val) {
$val = $val . $val;
}
add_filter_to_function('foo','filter');
foo(); //returns "barbar"
And then anywhere foo() is used, it would return filtered value without changing code that calls foo() to something like foo() . foo() and without changing the function itself
In PHP, there is a RunKit extension (runkit_function_redefine() in particular for your question) which allow you to manipulate with code's objects (such as function or classes) on the fly.
But I think you're doing something wrong if you need to change your function's code on that way - so may be you should reconsider your goal and resolve your original problem with another tools.
If you need to call your function with some parameters in some special cases, you can use something like:
function foo($x, $y)
{
//do stuff
}
function bar($x, $y, $z)
{
//do stuff with $z?
foo($x, $y);
}
and use bar() instead of foo() then - in certain places (which you need to adjust)
You cannot internally change the return value of a function, if it's static.
If you had foo($var), you could change the state of $var, and everytime you call foo($var) lately, you would recieve the new value, but in your case it's almost not possible.
You have to call the other function everytime you need double value:
function foo() {
return 'bar';
}
function filter($func) {
return $func.$func;
}
echo filter(foo());
Turn your function into an object method and then the add_filter_to_function would add the filter to the object.
Then when you called the function it would be able to use the filters that have been assigned to the object the function belongs to.
You could simply concatenate the value on itself:
$val = foo();
$val .= $val;
or if your function really needs to have a double value returned, then you should probably look at refactoring your foo() function, because it doesn't seem to do what you want.
Either that, or accept one of the other answers that tells you to wrap foo() around another function.

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

More About PHP OOP - Classes within Classes

I have been told that a class cannot be defined within a class in PHP. However, in my own example this seems to work which has me confused:
class_test.php:
require('class_1.php');
new class_1
//Need $missing_variable here.
class_1.php
class class_1{
public function function_1(){
function callback_function(){
echo "A Callback";
$missing_variable = "Where Did I Go?";
}
require('class_2.php');
new class_2('callback_function');
}
public function __construct(){
$this->function_1();
}
}
class_2.php
class class_2{
public function __construct($callback){
echo "Hello World - ";
call_user_func($callback);
}
}
Loading class_test.php prints out
Hello World - A Callback
Question: How do I define $missing_variable such that I can get it where I need it?
In case anyone in the future has a similar problem, however unlikely that may be, I want to link to the codepad from below that shows the $missing_variable echo'd from outside the classes:
http://codepad.org/tRk0XWG7
Thanks again everyone.
Note: This is a follow up.
You can declare a class within a function. That's known as conditional declaration, i.e. only if the function is called will the class be declared. It doesn't make much of a difference then whether you include a file with the class declaration or if you type out the code inside the function.
This does not mean however that the classes share any sort of scope or data. Only the declaration is conditionally nested, it still has the same functionality and scope as explained before.
Your confusion about the callback can be explained by the same thing. When class_1::function_1 is executed the first time, the function callback_function is being defined. This is a regular global function that can be called from anywhere. It's not bound to the class in any way. You will also notice that you cannot execute class_1::function_1 a second time, PHP will complain that callback_function already exists when you're trying to declare it again.
As for the comment in the source code //How do I declare this variable so that it is available where I need it?: You don't. That variable is a local variable inside a function. It's only in scope inside the function. You can return its value from the function like any other return value if you want to. (You could make it global, but for the love of god don't!) If you need that value somewhere else, don't declare it as a variable inside a function, because only the function can access it then.
You would return $missing_variable in a few places. See below. (This isn't the only way to do it, mind you)
http://codepad.org/tf08Vgdx
<?
class class_2{
public function __construct($callback){
echo "Hello World - ";
$missing = $callback();
$this->missing = $missing;
}
}
class class_1{
public function function_1(){
function callback_function(){
echo "A Callback. ";
$missing_variable = "Where Did I Go?";
return $missing_variable;
}
$class2 = new class_2('callback_function');
return $class2->missing;
}
public function __construct(){
$this->missing = $this->function_1();
}
}
$class = new class_1();
echo $class->missing;

Pass a function by reference in 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.

Categories