Les fonctions anonymes récursives en PHP

Comment une fonction anonyme peut-elle s'appeler elle-même ?

28 décembre 2013

Depuis PHP 5.3, les fonctions anonymes (instances de la classe Closure) sont l'un des éléments moteurs du langage. On peut les utiliser comme fonction de callback, pour faire du lazy load, des "vraies" closures ou plus simplement pour exécuter un algorithme dont l'utilisation ne nécessite pas la création d'une fonction nommée dans le scope global.

Puisque cette fonction n'a pas de nom, comment faire pour l'appeler de façon récursive ?

Fonction anonyme récursive : ce qui ne fonctionne pas

$f = function($i = 3){

	/* Attention aux boucles infinies */
	if ($i == 0)
	{
		return;
	}

	echo $i;
	$f(--$i);
};

$f(); // Notice: Undefined variable: f, Fatal error: Function name must be a string
	

Et oui ! Impossible pour la fonction de s'utiliser elle-même par le nom de la variable qui la référence car elle n'existe pas encore pendant sa propre définition.

Pour palier à ce problème nous allons utiliser le mot clé "use". Le mot clé "use" lié à une fonction anonyme (à ne pas confondre avec celui utilisé pour les namespaces) permet d'accéder à des variables définies dans le scope qui contient la définition de cette fonction.

Fonction anonyme : le mot clé use

$a = 42;

$o = new stdClass();
$o->foo = 'bar';

$f = function() use ($a, $o, &$b){

	echo 'a = '.$a.' b = '.$b.' o = '.$o->foo.'
'; }; $b = 1337; $f(); // affichage : a = 42 b = 1337 o = bar $o->foo = 'baz'; $a++; $b++; $f(); // affichage : a = 42 b = 1338 o = baz

Cet exemple nous apprend trois choses très importantes :

  • Les objets ($o) sont passés par référence alors que les scalaires ($a) le sont par copie. Dans les deux cas il faut que les variables soient déclarées avant la fonction anonyme sous peine d'erreurs.
  • En déclarant explicitement un passage par référence (&$b), la variable est utilisable même si elle n'existe pas encore pendant la déclaration de la fonction anonyme. Ceci est valable aussi bien avec les objets qu'avec les scalaires.

Avec ceci nous avons maintenant la solution pour faire de la récursivité avec une fonction anonyme : il suffit d'indiquer à notre fonction d'utiliser une référence vers elle-même. Ainsi, peut importe que la variable $f ne soit pas encore déclarée, elle sera quand même résolue.

Fonction anonyme récursive : la solution

$f = function($i = 3) use (&$f){

	/* Attention aux boucles infinies */
	if ($i == 0)
	{
		return;
	}

	echo $i;
	$f(--$i);
};

$f(); // affichage : 321
	

A bientôt !

Par
Créateur et administrateur.

Dans la même catégorie

Formater un tableau pour CURLOPT_POSTFIELDS
Email avec pièce jointe en PHP
PHP : modifier les attributs privés d'un objet
Tester l'existence d'un fichier dans l'include path
Convertir récursivement un objet PHP en tableau
PHP : formater un tableau en CSV
Comment envoyer un mail en ligne de commande ?
RSYNC : Comment synchroniser des fichiers à travers une connexion ssh ?
Exécuter un code PHP en ligne de commande
Doctrine 2 : générer les classes PHP depuis la base de données
Comment catcher les erreurs en PHP ?
Doctrine 2 : comment afficher la requête SQL ?
Comment construire une URL sans caractères spéciaux en PHP ?
Comment lister les fichiers PHP inclus sur ma page ?
Requête HTTP asynchrone en PHP
La résolution statique à la volée ou Late Static Bindings
Trouver les jours fériés français en PHP
Comment allumer son ordinateur à distance en PHP ?
Comment utiliser la balise meta viewport ?
Une version mobile de mon site avec le Zend Framework
Doctrine et le Zend Framework : Présentation, intégration et utilisation
Créer son flux RSS simplement avec Zend_Feed
Appliquer un layout sur un mail avec le Zend Framework
Comment lancer une requête multi-bases avec les fonctions MySQL ?
Implode / Explode : Du tableau à la chaine de caractères, de la chaine de caractères au tableau

Commentaire(s)