I have a list of functions a(), b(), c()
I have a main() function.
Depending on case, I need to pass a different function to main() to use.
In javascript it would be:
var a = function(){}
var b = function(){}
var c = function(){}
var func = (some logic) a, b or c;
main(func);
How do I do that in php5.3?
I am trying to avoid using
$func_name = "a";
main($func_name){
$func_name();
}
Or may be it is the best way, and I should not use closures of any type?
Same idea in PHP 5.3, as you can create anonymous functions:
$sayHello = function($var)
{
echo "Hello ", $var;
};
// Logic here to determine what $func is set to
$func = $sayHello;
function callCustom($function)
{
if(!is_callback($function))
{
// throw exception
}
$function("World");
}
callCustom($func); // Hello World
Try this:
$a = function(){};
$b = function(){};
$c = function(){};
switch (rand(0, 2)) {
case 0: $func = $a; break;
case 1: $func = $b; break;
case 2: $func = $c; break;
}
var_dump($func);
You can see a working example here http://codepad.viper-7.com/Ut5yGQ
Note: I used var_dump instead of main as main is undefined
In PHP, anything that is "callable" (is_callableDocs) can be called (invoked). The manual often names these parameters as Callback, a pseudo-type in PHPDocs.
You can use any of the different callbacks and pass them as a function parameter:
function main($callback)
{
call_user_func($callback);
}
Then your function will work with any valid PHP callback.
Next to that, functions can be called with variables, some examples:
Variable Function Call:
function name() {};
$function = 'name'; # function name as string
$function(); # invoke
Anonymous Function as Variable Function Call:
$function = function() {}; # define function
$function(); # invoke
See as well Variable FunctionsDocs.
Related
How to pass method callback as a parameter to another method? All the examples I've seen use functions, but not methods. What I've tried is:
call_user_func($this, 'method_name', [$param1, $param2,...]);
Also is there another, more elegant way, like just passing $this->method_name as a parameter?
I know I could add the callback as:
function () use ($param1, $param2,...) {
return $this->method_name($param1, $param2);
}
But I would like to omit the closure part.
You could also use [$obj, 'method'] as an callback, bind to an object.
class A {
public $b = 'test';
public function callback() {
echo $this->b;
}
}
$a = new A();
$f = [$a, 'callback'];
$f();
I'm trying to store anonymous functions in a static array property of my class. These functions should be invoked later by their index, but calling
self::$arr['index']()
just doesn't work, while
$a = self::$arr['index'];
$a();
does!
This doesn't work:
class A {
private static $func = array('a' => '');
public function __construct() {
self::$func['a'] = create_function('$str', 'echo "$str";');
}
public function go($str) {
self::$func['a']($str); // Call the function directly
}
}
$a = new A();
$a->go("hooray"); // Outputs "Undefined variable: func"
But this does:
class A {
private static $func = array('a' => '');
public function __construct() {
self::$func['a'] = create_function('$str', 'echo "$str";');
}
public function go($str) {
$a = self::$func['a']; // Pass the function name to a variable
$a($str); // Call the function via the variable
}
}
$a = new A();
$a->go("hooray"); // Outputs "hooray"
Why?
I'm using PHP Version 5.4.3
this is the behavior of php's parser
$functionName['a'] = "hello";
self::$functionName['a']();
calls
self::hello();
... the very sad thing is that in php you can't do this:
(self::$functionName['a'])(); // doesn't work in php :(
as you can do in javascript, for example
what you can do is... use a temporary variable like you said
$a = self::$func['a'];
$a($parameter);
or
call_user_func(self::$func['a'], $parameter);
hope this helps...
in latest phps these features were added
$a['sss'] = function(){ echo 'bla'; };
$a['sss']();
class Bla
{
private $a;
function test()
{
$this->a['sss'] = function(){ echo 'bla2'; };
$this->a['sss']();
}
}
$c = new Bla();
$c->test();
and they work properly... so for some reason, this syntax doesn't work only when using the scope resolution operator ( ClassName:: self:: etc)
Well, in php you simply can not do that, it is a php feature. But you can use call_user_func or its relatives:
return call_user_func(self::$func['$a'], $str);
This is a consequence of how the PHP parser currently works. Since the function call () is evaluated before the static operator ::, you end up with the parser attempting to reference the local variable $func instead, and then giving you the error about $func being undefined (which it is, since there is no variable named $func in the method).
As you've discovered, you can solve this by doing two separate statements.
i have this class (simple one just for example):
<?
class Test {
public function test1($a) {
$gen = function() {
$gen = function() {
global $a; // no effect
echo 'a='. $a; // how could i access $a from test1 parameter without passing?
};
$gen();
};
$gen();
}
};
$x = new Test();
$x->test1(123);
is there a way to access $a from test1 paramter inside last $gen function without passing it to the $gen() function?
Anonymous functions in PHP don't have an implicit variable scope like JavaScript does, so you need to specify which variables from the parent scope are needed. You do this with the use syntax:
$var = 123;
$fn = function() use ($var) {
// you can use $var here
}
$fn();
See also: Closures and scoping
You are missing the use statement. Refere to the 3rd example on PHP's documentation on closures.
This will work:
<?php
class Test {
public function test1($a) {
$gen = function() use ($a) {
$gen = function() use($a) {
echo 'a='. $a; // how could i access $a from test1 parameter without passing?
};
$gen();
};
$gen();
}
};
$x = new Test();
$x->test1(123);
I have an anonymous function which is supposed to call itself. However, I have no variable or function name at hand, so I was hoping to find a function that could do return "this" in context of functions. Is there such a thing?
Here's an example:
$f = function() use($bar, $foo) {
// call this function again.
};
Calling like this:
call_user_func(__FUNCTION__);
Leads to this:
Warning: call_user_func() expects parameter 1 to be a valid callback,
function '{closure}' not found or invalid function name
If I try to put $f in the use-list, then it says the variable is not defined (because it is not yet).
__FUNCTION__ cannot be used in anonymous functions
Pass the variable holding the anonymous function as a reference in the 'use' clause....
$f = function() use($bar, $foo, &$f) {
$f();
};
Tip of the hat to this answer.
Okay, I found out the way to do this:
$f = function() use(&$f) {
$f();
};
$f();
The key thing is to pass $f as a reference. Thus PHP does not try to pass a value but a reference to a memory slot.
I have an anonymous function which is supposed to call itself.
I prefer to use call_user_func_array(__FUNCTION__, $params); when calling a recursive function.
As your example doesn't have any arguments then i guess call_user_func(__FUNCTION__); would be better suited.
You would expect and hope the following code would work but that would be too easy.
$bar = 10;
$foo = 0;
$f = function() use (&$bar,$foo) {
if($bar){ // condition needed to prevent infinite loop
echo $bar-- . PHP_EOL;
call_user_func(__FUNCTION__); // wont work
}
};
$f();
The __FUNCTION__ "Magic constant" is unavailable to closures so the code needs to be adapted to allow the passing of the function variable. we can make the function available by passing it as a regular argument or via the use statement.
Function passed as argument
$bar = 10;
$foo = 0;
$f = function( $__FUNCTION__ = null ) use (&$bar, $foo) {
if($__FUNCTION__ && $bar){
echo $bar-- . PHP_EOL;
call_user_func( $__FUNCTION__, $__FUNCTION__);
}
};
$f ( $f );
Function passed via use statement
$bar = 10;
$foo = 0;
$__FUNCTION__ = function() use (&$bar, $foo, &$__FUNCTION__) {
if($bar){
echo $bar-- . PHP_EOL;
call_user_func( $__FUNCTION__ );
}
};
$__FUNCTION__();
Working example, click edit-> ideone it! to re-run code.
http://www.php.net/manual/en/language.constants.predefined.php
Edit: Posted before code was given. Of course it doesn't work on anonymous functions.
call_user_func(__FUNCTION__, $param1, $param2);
call_user_func_array(__FUNCTION__, $params);
function i_dont_know() {
call_user_func(__FUNCTION__,$params);
//or
$funcname = __FUNCTION__;
$funcname($params);
}
What are the differences between closures in JS and closures in PHP? Do they pretty much work the same way? Are there any caveats to be aware of when writing closures in PHP?
One difference is how both cope with storing the context in which an anonymous function is executed:
// JavaScript:
var a = 1;
var f = function() {
console.log(a);
};
a = 2;
f();
// will echo 2;
// PHP
$a = 1;
$f = function() {
echo $a;
};
$a = 2;
$f();
// will result in a "PHP Notice: Undefined variable: a in Untitled.php on line 5"
To fix this notice you'll have to use the use syntax:
$a = 1;
$f = function() use ($a) {
echo $a;
};
$a = 2;
$f();
// but this will echo 1 instead of 2 (like JavaScript)
To have the anonymous function behave somehow like the JavaScript counterpart you'll have to use references:
$a = 1;
$f = function() use (&$a) {
echo $a;
};
$a = 2;
$f();
// will echo 2
I think this is the most striking difference between JavaScript and PHP closures.
Second difference is that every JavaScript closure has a this context available which means, that you can use this inside the closure itself (although it's often quite complicated to figure out what this actually refers to) - PHP's current stable version (PHP 5.3) does not yet support $this inside a closure, but PHP's upcoming version (PHP 5.4) will support $this binding and rebinding using $closure->bind($this) (See the Object Extension RFC for more info.)
Third difference is how both languages treat closures assigned to object properties:
// JavaScript
var a = {
b: function() {}
};
a.b(); // works
// PHP
$a = new stdClass();
$a->b = function() {};
$a->b(); // does not work "PHP Fatal error: Call to undefined method stdClass::b() in Untitled.php on line 4"
$f = $a->b;
$f(); // works though
The same is true if closures are assigned to properties in class definitions:
class A {
public $b;
public function __construct() {
$this->b = function() {};
}
public function c() {
$this->b();
}
}
$a = new A();
// neither
$a->b();
// nor
$a->c();
// do work
Fourth difference: JavaScript Closures are full fledged objects, wheres in PHP they are restricted objects. For instance, PHP Closures cannot have properties of their own:
$fn = function() {};
$fn->foo = 1;
// -> Catchable fatal error: Closure object cannot have properties
while in JavaScript you can do:
var fn = function() {};
fn.foo = 1;
fn.foo; // 1
Fifth difference: Returned closures can be immediately called upon in Javascript:
var fn = function() { return function() { alert('Hi');}}
fn()();
Not in PHP:
$fn = function() { return function() { echo('Hi');};};
$fn()(); // syntax error
The only thing I've found in PHP (that is totally cool and really handy!) is the ability to use them as getters and setters in classes which was always a nightmare to achieve before, JavaScript can be used in the same way but they do both act almost identically from what I've seen.
I'm not sure about the namespacing convention differences between the two but as #Rijk pointed out there is a section on the PHP website dedicated to them
<?php
class testing {
private $foo = 'Hello ';
public $bar = 'Bar';
#Act like a getter and setter!
public static $readout = function ($val = null) {
if (!empty($val)) {
testing::$readout = $val;
}
return testing::$readout;
}
}
They are also really great for...
Looping through items with a controller rather than a new for/each loop on the page
Great for supplying as arguments to functions/classes
Whats annoying about them is...
You can't typecast them, since they're just functions...
They do pretty much work the same way. Here's more information about the PHP implementation: http://php.net/manual/en/functions.anonymous.php
You can use a closure (in PHP called 'anonymous function') as a callback:
// return array of ids
return array_map( function( $a ) { return $a['item_id']; }, $items_arr );
and assign it to a variable:
$greet = function( $string ) { echo 'Hello ' . $string; }; // note the ; !
echo $greet('Rijk'); // "Hello Rijk"
Furthermore, anonymous function 'inherit' the scope in which they were defined - just as the JS implementation, with one gotcha: you have to list all variables you want to inherit in a use():
function normalFunction( $parameter ) {
$anonymous = function() use( $parameter ) { /* ... */ };
}
and as a reference if you want to modify the orignal variable.
function normalFunction( $parameter ) {
$anonymous = function() use( &$parameter ) { $parameter ++ };
$anonymous();
$parameter; // will be + 1
}