To recursively call a closure, use this code.
<?php
$recursive = function () use (&$recursive){
// The function is now available as $recursive
}
?>
This DOES NOT WORK
<?php
$recursive = function () use ($recursive){
// The function is now available as $recursive
}
?>
Fonctions anonymes
Les fonctions anonymes, aussi appelées fermetures ou closures permettent la création de fonctions sans préciser leur nom. Elles sont particulièrement utiles comme fonction de rappel, mais leur utilisation n'est pas limitée à ce seul usage.
Exemple #1 Exemples avec des fonctions anonymes
<?php
echo preg_replace_callback('~-([a-z])~', function ($match) {
return strtoupper($match[1]);
}, 'bonjour-le-monde');
?>
L'exemple ci-dessus va afficher :
outputs bonjourLeMonde
Les fermetures peuvent aussi être utilisées comme valeurs de variables. PHP va automatiquement convertir ces expressions en objets Closure. Assigner une fermeture à une variable est la même chose qu'un assignement classique, y compris pour le point-virgule final.
Exemple #2 Assignation de fonction anonyme à une variable
<?php
$greet = function($name)
{
printf("Bonjour %s\r\n", $name);
};
$greet('World');
$greet('PHP');
?>
L'exemple ci-dessus va afficher :
outputs bonjourLeMonde
Les fermetures peuvent hériter des variables du contexte de leur parent. Ces variables doivent alors être déclaré dans la signature de la fonction. L'héritage du contexte parent n'est pas la même chose que les variables de l'environnement global. Les variables globales existent dans le contexte global, qui est le même, quelque que soit la fonction qui s'exécute. Le contexte parent d'une fermeture est la fonction dans laquelle la fonction a été déclaré (par nécessairement la fonction qui appelle). Voyez l'exemple ci-dessous :
Exemple #3 Fonctions anonymes et contexte
<?php
// Un panier d'achat simple, qui contient une liste de produits
// choisis et la quantité désirée de chaque produite. Il inclut
// une méthode qui calcule le prix total des éléments dans le panier
// en utilisant une fonction de rappel anonyme.
class Panier
{
const PRICE_BEURRE = 1.00;
const PRICE_LAIT = 3.00;
const PRICE_OEUF = 6.95;
protected $products = array();
public function add($product, $quantity)
{
$this->products[$product] = $quantity;
}
public function getQuantity($product)
{
return isset($this->products[$product]) ? $this->products[$product] :
FALSE;
}
public function getTotal($tax)
{
$total = 0.00;
$callback =
function ($quantity, $product) use ($tax, &$total)
{
$pricePerItem = constant(__CLASS__ . "::PRICE_" .
strtoupper($product));
$total += ($pricePerItem * $quantity) * ($tax + 1.0);
};
array_walk($this->products, $callback);
return round($total, 2);;
}
}
$mon_panier = new Panier;
// Ajout d'élément au panier
$mon_panier->add('beurre', 1);
$mon_panier->add('lait', 3);
$mon_panier->add('oeuf', 6);
// Affichage du prix avec 5.5% de TVA
print $mon_panier->getTotal(0.055) . "\n";
?>
L'exemple ci-dessus va afficher :
54.54
Les fonctions anonymes sont actuellement implémentée en utilisant la classe Closure. C'est un détail d'implémentation, et il est recommandé de ne pas s'appuyer dessus.
Note: Les fonctions anonymes sont disponibles depuis PHP 5.3.0.
Note: Il est possible d'utiliser les fonctions func_num_args(), func_get_arg() et func_get_args() dans une fermeture.
Fonctions anonymes
28-Oct-2009 04:40
13-Oct-2009 12:22
be aware of Fatal error: Using $this when not in object context when using in closures
http://wiki.php.net/rfc/closures/removal-of-this
07-Oct-2009 02:41
The text above the third example tries to explain that anonymous functions can inherit variables from the parent scope, but fails to properly explain how this is done: namely using the "use" keyword in the function definition.
The following page has a much more detailed explanation of closures in PHP 5.3:
http://wiki.php.net/rfc/closures
03-Oct-2009 05:06
Very easy way to get the netstat (windows)... yes, this could be a function, but as an example, here it is in closure form...
<?php
$netstat = function($return = null, $precision = 2) {
// supplement function
$_convert = function ($bytes) use ($precision) {
$i = 0; $iec = array('b', 'kb', 'mb', 'gb', 'tb', 'pb', 'eb', 'zb', 'yb');
while (($bytes / 1024) > 1): $bytes = $bytes / 1024; $i++; endwhile;
return round(substr($bytes, 0, strpos($bytes, '.') + 4), $precision) . ' ' . strtoupper($iec[$i]);
};
foreach (explode("\n", `netstat -e`) as $d) {
if (preg_match('/^Bytes([\s].+)([0-9])([\s].+)([0-9])/', $d, $m)) {
switch ($return) {
case 'sent': return $_convert(trim($m[1].$m[2])); break;
case 'recv': return $_convert(trim($m[3].$m[4])); break;
default: return array('sent' => $_convert(trim($m[1].$m[2])),
'recv' => $_convert(trim($m[3].$m[4]))); break;
}
}
}
};
?>
09-Sep-2009 10:52
<?php
/**
* Using closures to dynamically extend objects
*
*/
class ClosureTest{
public $member = 'test';
protected $protectedMember = 'protectedtest';
public function __call($method, $args)
{
return call_user_func_array( $this->$method, $args);
}
}
$object = new ClosureTest();
$object->closure = function() use ($object){
return $object->member;
};
echo $object->closure();
//Output: 'test'
/**
* This won't work, you can not access protected/private members, which is fine.
*/
$object->closureAccessProtected = function() use ($object){
return $object->protectedMember;
};
$object->closureAccessProtected();
?>
10-Aug-2009 09:34
Ulderico had it almost right. To avoid confusing the interpreter, when using a simple closure stored in a $variable, you must invoke the nameless function using the function syntax.
<?php
$helloworld = function(){
return "each hello world is different... ".date("His");
};
echo $helloworld( );
?>
Note the empty actual-parameter list in the "echo". NOW IT WORKS.
03-Aug-2009 09:50
If you want to check whether you're dealing with a closure specifically and not a string or array callback you can do this:
<?php
$isAClosure = is_callable($thing) && is_object($thing);
?>
29-Jul-2009 10:51
Unfortunately, you can't get a pointer to a function, the only function pointers are ones which use anonymous functions as they're created.
This wont work:
<?php
$info = phpinfo;
$info();
//or
function foo() {
echo 'bar';
}
$foo = foo;
$foo();
?>
Because of the behavior of $foo(), it will assume $foo is a string, and try to run the function with the name stored in the string.
14-Jul-2009 02:43
Perhaps you'll find yourself wanting doing a wicked thing like:
<?php
$helloworld = function(){
return "each hello world is different... ".date("His");
};
echo $helloworld;
?>
which throws:
Catchable fatal error: Object of class String could not be converted to string
OK... Here's the way of doing this.
<?php
class Helloworld{
function __toString(){
return("each hello world is different...".date("His"));
}
}
$helloworld = new Helloworld();
echo $helloworld;
sleep(5);
echo $helloworld;
?>
30-Jun-2009 12:49
Example using uasort.
<?php
// Usual method.
function cmp($a, $b) {
return($a > $b);
}
uasort($array, 'cmp');
// New
uasort($array, function($a, $b) {
return($a > $b);
});
?>
19-Jun-2009 09:55
When using anonymous functions as properties in Classes, note that there are three name scopes: one for constants, one for properties and one for methods. That means, you can use the same name for a constant, for a property and for a method at a time.
Since a property can be also an anonymous function as of PHP 5.3.0, an oddity arises when they share the same name, not meaning that there would be any conflict.
Consider the following example:
<?php
class MyClass {
const member = 1;
public $member;
public function member () {
return "method 'member'";
}
public function __construct () {
$this->member = function () {
return "anonymous function 'member'";
};
}
}
header("Content-Type: text/plain");
$myObj = new MyClass();
var_dump(MyClass::member); // int(1)
var_dump($myObj->member); // object(Closure)#2 (0) {}
var_dump($myObj->member()); // string(15) "method 'member'"
$myMember = $myObj->member;
var_dump($myMember()); // string(27) "anonymous function 'member'"
?>
That means, regular method invocations work like expected and like before. The anonymous function instead, must be retrieved into a variable first (just like a property) and can only then be invoked.
Best regards,
