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 fonctions de rappel, mais leur utilisation n'est pas limitée à ce seul usage.

Les fonctions anonymes sont implémentées en utilisant la classe Closure.

Exemple #1 Exemples avec des fonctions anonymes

<?php
echo preg_replace_callback('~-([a-z])~', function ($match) {
    return 
strtoupper($match[1]);
}, 
'bonjour-le-monde');
?>

Les fonctions anonymes 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');
?>

Les fonctions anonymes peuvent hériter des variables du contexte de leur parent. Ces variables doivent alors être passées dans la construction de langage use. A partir de PHP 7.1, ces variables ne doivent pas inclure de superglobals, $this, ou des variables ayant le même nom qu'un paramètre.

Exemple #3 Héritage de variable depuis le contexte parent

<?php
$message 
'hello';

// Pas de "use"
$example = function () {
    
var_dump($message);
};
$example();

// Hérite $message
$example = function () use ($message) {
    
var_dump($message);
};
$example();

// La valeur de la variable héritée est définie lors que la fonction est 
// définie non quand elle est appelée
$message 'world';
$example();

// Réinitialisation de la variable message
$message 'hello';

// Héritage par référence
$example = function () use (&$message) {
    
var_dump($message);
};
$example();

// Le changement de valeur dans le contexte parent est reflété lors de 
// l'appel de la fonction.
$message 'world';
$example();

// Les fonctions anonymes peuvent accépté des arguments classiques
$example = function ($arg) use ($message) {
    
var_dump($arg ' ' $message);
};
$example("hello");
?>

L'exemple ci-dessus va afficher quelque chose de similaire à :

Notice: Undefined variable: message in /example.php on line 6
NULL
string(5) "hello"
string(5) "hello"
string(5) "hello"
string(5) "world"
string(11) "hello world"

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, quelle que que soit la fonction qui s'exécute. Le contexte parent d'une fonction anonyme est la fonction dans laquelle la fonction a été déclarée (pas nécessairement celle qui appelle). Voyez l'exemple ci-dessous :

Exemple #4 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 produit. 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($total2);
    }
}

$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";
// Le résultat sera 54.29
?>

Exemple #5 Liage automatique de $this

<?php

class Test
{
    public function 
testing()
    {
        return function() {
            
var_dump($this);
        };
    }
}

$object = new Test;
$function $object->testing();
$function();
    
?>

L'exemple ci-dessus va afficher :

object(Test)#1 (0) {
}

Résultat de l'exemple ci-dessus en PHP 5.3 :

Notice: Undefined variable: this in script.php on line 8
NULL

Depuis PHP 5.4.0, lorsque déclarée dans le contexte d'une classe, la classe courante est automatiquement liée, la rendant $this disponible dans le contexte de la fonction. Si ce liage automatique de la classe courante n'est pas souhaité, alors les fonctions anonymes statiques peuvent être utilisées à la place.

Les fonctions anonymes statiques

Depuis PHP 5.4.0, les fonctions anonymes peuvent être déclarées statiquement. Ceci permet de ne pas lier automatiquement la classe courante à la fonction. Les objets peuvent aussi ne pas être liés lors de l'exécution.

Exemple #6 Tentative d'utiliser $this dans une fonction anonyme statique

<?php

class Foo
{
    function 
__construct()
    {
        
$func = static function() {
            
var_dump($this);
        };
        
$func();
    }
};
new 
Foo();

?>

L'exemple ci-dessus va afficher :

Notice: Undefined variable: this in %s on line %d
NULL

Exemple #7 Tentative de liage d'un objet à une fonction anonyme statique

<?php

$func 
= static function() {
    
// function body
};
$func $func->bindTo(new StdClass);
$func();

?>

L'exemple ci-dessus va afficher :

Warning: Cannot bind an instance to a static closure in %s on line %d

Historique

Version Description
7.1.0 Les fonctions anonymes peuvent ne pas se fermer superglobals, $this, ou toute variable avec le même nom qu'un paramètre.
5.4.0 Les fonctions anonymes peuvent utiliser $this, comme si elles étaient déclarées statiquement.
5.3.0 Les fonctions anonymes deviennent disponibles.

Notes

Note: Il est possible d'utiliser les fonctions func_num_args(), func_get_arg() et func_get_args() dans une fonction anonyme.