Les closures et les classes anonymes en PHP objet

Dans cette nouvelle leçon, nous allons aborder la notion de classes anonymes. Pour bien comprendre comment vont fonctionner les classes anonymes, nous allons en profiter pour présenter les fonctions anonymes ou « closures ».

 

Découverte des fonctions anonymes et de la classe closure

Les fonctions anonymes, qu’on appelle également des closures, sont des fonctions qui ne possèdent pas de nom.

On va créer une fonction anonyme de la même façon que l’on crée une fonction normale à la différence qu’on ne va ici pas préciser de nom.

Exemple et syntaxe de création d'une fonction anonyme en PHP

A ce stade, vous devriez déjà vous poser deux questions : quel est l’intérêt de créer de telles fonctions et comment peut-on les exécuter ou les appeler si elles ne possèdent pas de nom ?

Les closures en PHP ont été de manière historique principalement utilisées en tant que fonction de rappel car les fonctions de rappel. Une fonction de rappel est une fonction qui va être appelée par une autre fonction.

Notez que les fonctions anonymes sont implémentées en utilisant la classe prédéfinie Closure.

 

Appeler une fonction anonyme

Depuis PHP 7, il existe trois grands moyens simples d’appeler une fonction anonyme :

  • En les auto-invoquant de manière similaire au langage JavaScript ;
  • En les utilisant comme fonctions de rappel ;
  • En les utilisant comme valeurs de variables.

Auto-invoquer une fonction anonyme

Depuis PHP 7, on peut auto-invoquer nos fonctions anonymes, c’est-à-dire faire en sorte qu’elles s’appellent elles-mêmes de manière automatique à la manière du JavaScript.

Pour cela, il va suffire d’entourer notre fonction anonyme d’un premier couple de parenthèses et d’ajouter un autre couple de parenthèses à la suite du premier couple comme cela :

<!DOCTYPE html>
<html>
    <head>
        <title>Cours PHP & MySQL</title>
        <meta charset="utf-8">
        <link rel="stylesheet" href="cours.css">
    </head>
    
    <body>
        <h1>Titre principal</h1>
        <?php
            (function(){
                echo 'Fonction anonyme bien exécutée';
            })();
        ?>
        <p>Un paragraphe</p>
    </body>
</html>

 

Exemple de fonction anonyme auto invoquée en PHP

Créer des fonctions anonymes auto-invoquées va être très intéressant lorsqu’on ne va vouloir effectuer une tâche qu’une seule fois. Dans ce cas-là, en effet, il n’y a aucun intérêt de créer une fonction classique.

Par ailleurs, dans certains codes, nous n’allons pas pouvoir appeler une fonction manuellement mais allons vouloir que la fonction s’exécute automatiquement. Dans ces cas-là, utiliser la syntaxe ci-dessus va être très pertinent.

Utiliser une fonction anonyme comme fonction de rappel

Une fonction de rappel est une fonction qui va être appelée par une autre fonction. Pour cela, nous allons passer notre fonction de rappel en argument de la fonction appelante.

Les fonctions de rappel peuvent être de simples fonctions nommées, des fonctions anonymes ou encore des méthodes d’objets ou des méthodes statiques.

Dans le cas d’une fonction de rappel nommée, nous passerons le nom de la fonction de rappel en argument de la fonction appelante. Dans le cas d’une fonction de rappel anonyme, nous enfermerons la fonction dans une variable qu’on passera en argument de la fonction qui va l’appeler.

Bien évidemment, toutes les fonctions n’acceptent pas des fonctions de rappel en arguments mais seulement certaines comme la fonction usort() par exemple qui va servir à trier un tableau en utilisant une fonction de comparaison ou encore la fonction array_map() qui est la fonction généralement utilisée pour illustrer l’intérêt des closures.

La fonction array_map() va appliquer une fonction sur des éléments d’un tableau et retourner un nouveau tableau. On va donc devoir passer deux arguments à celle-ci : une fonction qui va dans notre cas être une closure et un tableau. Prenons immédiatement un exemple.

<!DOCTYPE html>
<html>
    <head>
        <title>Cours PHP & MySQL</title>
        <meta charset="utf-8">
        <link rel="stylesheet" href="cours.css">
    </head>
    
    <body>
        <h1>Titre principal</h1>
        <?php
            /*La closure ci-dessous accepte un nombre en argument et
             *retourne son carré*/
            $squ = function(float $x){
                return $x**2;
            };
            
            //Définition d'un tableau
            $tb = [1, 2, 3, 4, 5];
            
            //array_map() exécute notre closure sur chaque élément du tableau
            $tb_squ = array_map($squ, $tb);
            
            echo '<pre>';
            print_r($tb_squ);
            echo '</pre>';
        ?>
        <p>Un paragraphe</p>
    </body>
</html>

 

Exemple d'utilisation de fonction anonyme comme fonction de rappel en PHP

Dans cet exemple, on commence par créer une closure dont le rôle est de calculer et de renvoyer le carré d’un nombre. On affecte notre closure à la variable $squ puis on crée ensuite une variable tableau stockant cinq chiffres.

Finalement, on utilise notre fonction array_map() en lui passant notre variable contenant notre fonction de rappel ainsi que notre tableau afin qu’elle renvoie un nouveau tableau et appliquant notre fonction de rappel à chaque élément du tableau passé.

On stocke le résultat renvoyé par array_map() dans une nouvelle variable $tb_squ qui est également une variable tableau et on affiche son contenu avec print_r().

Appeler des fonctions anonymes en utilisant des variables

Lorsqu’on assigne une fonction anonyme en valeur de variable, notre variable va automatiquement devenir un objet de la classe prédéfinie Closure.

La classe Closure possède des méthodes qui vont nous permettre de contrôler une closure après sa création. Cette classe possède également une méthode magique __invoke() qui va ici s’avérer très utile puisqu’on va donc pouvoir exécuter nos closures simplement.

Je vous rappelle ici que la méthode magique __invoke() va s’exécuter dès qu’on se sert d’un objet comme d’une fonction.

Cela va nous permettre d’utiliser la syntaxe suivante pour appeler nos fonctions anonymes :

<!DOCTYPE html>
<html>
    <head>
        <title>Cours PHP & MySQL</title>
        <meta charset="utf-8">
        <link rel="stylesheet" href="cours.css">
    </head>
    
    <body>
        <h1>Titre principal</h1>
        <?php
            $txt = function(){
                echo 'Fonction anonyme bien exécutée';
            };
            
            $squ = function(float $x){
                return 'Le carré de ' .$x. ' est ' .$x**2;
            };
            
            $txt();
            echo '<br>';
            echo $squ(3);
        ?>
        <p>Un paragraphe</p>
    </body>
</html>

 

On stocke une fonction anonyme dans une variable et on appelle la variable en PHP

Comme vous pouvez le constater, nos variables objets $txt et $squ sont utilisées comme fonctions pour exécuter les closures contenues à l’intérieur et les résultats sont bien renvoyés.

 

Définition et intérêt des classes anonymes

Les classes anonymes ont été implémentées récemment en PHP, puisque leur support n’a été ajouté qu’avec le PHP 7.

Les classes anonymes, tout comme les fonctions anonymes, sont des classes qui ne possèdent pas de nom.

Les classes anonymes vont être utiles dans le cas ou des objets simples et uniques ont besoin d’être créés à la volée.

Créer des classes anonymes va donc principalement nous faire gagner du temps et améliorer in-fine la clarté de notre code.

On va pouvoir passer des arguments aux classes anonymes via la méthode constructeur et celles-ci vont pouvoir étendre d’autres classes ou encore implémenter des interfaces et utiliser des traits comme le ferait une classe ordinaire.

Notez qu’on va également pouvoir imbriquer une classe anonyme à l’intérieur d’une autre classe. Toutefois, on n’aura dans ce cas pas accès aux méthodes ou propriétés privées ou protégées de la classe contenante.

Pour utiliser des méthodes ou propriétés protégées de la classe contenante, la classe anonyme doit étendre celle-ci. Pour utiliser les propriétés privées de la classe contenant dans la classe anonyme, il faudra les passer via le constructeur.

 

Créer et utiliser des classes anonymes

Voyons immédiatement comment créer et manipuler des classes anonymes à travers différents exemples.

<!DOCTYPE html>
<html>
    <head>
        <title>Cours PHP & MySQL</title>
        <meta charset="utf-8">
        <link rel="stylesheet" href="cours.css">
    </head>
    
    <body>
        <h1>Titre principal</h1>
        <?php
            //On crée une classe anonyme qu'on stocke dans une variable (objet)
            $anonyme = new class{
                public $user_name;
                public const BONJOUR = 'Bonjour ';
                
                public function setNom($n){
                    $this->user_name = $n;
                }
                public function getNom(){
                    return $this->user_name;
                }
            };
            
            $anonyme->setNom('Pierre');
            echo $anonyme::BONJOUR;
            echo $anonyme->getNom();
            echo '<br><br>';
            
            //Affiche les infos de $anonyme
            var_dump($anonyme);
        ?>
        <p>Un paragraphe</p>
    </body>
</html>

 

Création d'une classe anonyme en PHP

Ici, on commence avec un exemple simple en se contentant de déclarer une classe anonyme qu’on assigne à une variable qui devient de fait un objet.

Notre classe anonyme contient des propriétés, méthodes et constantes tout comme une classe classique.

Ensuite, on effectue différentes opérations simples : récupération et affichage des valeurs des propriétés, exécution des méthodes de notre classe anonyme, etc. afin que vous puissiez observer les différentes opérations que l’on peut réaliser.

Notez bien une nouvelle fois que le support des classes anonymes par le PHP est relativement récent : il est donc tout à fait possible que votre éditeur ne reconnaisse pas cette écriture (ce qui n’est pas grave en soi) ou que votre WAMP, MAMP, etc. n’arrive pas à l’exécuter si vous ne possédez une version PHP postérieure à la version 7.

On peut encore assigner une classe anonyme à une variable en passant par une fonction.

Dans ce cas-là, on pourra écrire quelque chose comme cela :

<!DOCTYPE html>
<html>
    <head>
        <title>Cours PHP & MySQL</title>
        <meta charset="utf-8">
        <link rel="stylesheet" href="cours.css">
    </head>
    
    <body>
        <h1>Titre principal</h1>
        <?php
            //On crée une classe anonyme qu'on stocke dans une variable objet
            function anonyme(){
                return new class{
                    public $user_name;
                    public const BONJOUR = 'Bonjour ';
                
                    public function setNom($n){
                        $this->user_name = $n;
                    }
                    public function getNom(){
                        return $this->user_name;
                    }
                };
            }
            
            $anonyme = anonyme();

            $anonyme->setNom('Pierre');
            echo $anonyme::BONJOUR;
            echo $anonyme->getNom();
            echo '<br><br>';
            
            //Affiche les infos de $anonyme
            var_dump($anonyme);
        ?>
        <p>Un paragraphe</p>
    </body>
</html>

 

Ce code est tout à fait comparable au précédent à la différence qu’on crée une fonction qui va retourner la définition de notre classe anonyme tout simplement.

Finalement, on peut également utiliser un constructeur pour passer des arguments à une classe anonyme lors de sa création.

<!DOCTYPE html>
<html>
    <head>
        <title>Cours PHP & MySQL</title>
        <meta charset="utf-8">
        <link rel="stylesheet" href="cours.css">
    </head>
    
    <body>
        <h1>Titre principal</h1>
        <?php
            //On crée une fonction qui retourne une classe anonyme
            function anonyme($n){
                return new class($n){
                    public $user_name;
                    public const BONJOUR = 'Bonjour ';
                
                    public function __construct($n){
                        $this->user_name = $n;
                    }
                    public function getNom(){
                        return $this->user_name;
                    }
                };
            }
            
            //On stocke le résultat de la fonction dans une variable objet
            $anonyme = anonyme('Pierre');
            echo $anonyme::BONJOUR;
            echo $anonyme->getNom();
            echo '<br><br>';
            
            //Affiche les infos de $anonyme
            var_dump($anonyme);
        ?>
        <p>Un paragraphe</p>
    </body>
</html>

 

Ici, on définit le même paramètre $n lors de la définition de notre fonction et de notre classe anonyme. On passe ensuite l’argument Pierre lors de l’affectation du résultat de notre fonction dans la variable $anonyme. Cet argument va être stocké dans la propriété $user_name de notre classe.

Finalement, retenez que dans le cas où une classe anonyme est imbriquée dans une autre classe, la classe anonyme doit l’étendre afin de pouvoir utiliser ses propriétés et méthodes protégées. Pour utiliser ses méthodes et propriétés privées, alors il faudra également les passer via le constructeur.

Regardez plutôt l’exemple suivant :

<!DOCTYPE html>
<html>
    <head>
        <title>Cours PHP & MySQL</title>
        <meta charset="utf-8">
        <link rel="stylesheet" href="cours.css">
    </head>
    
    <body>
        <h1>Titre principal</h1>
        <?php
            class Externe{
                private $age = 29;
                protected $nom = 'Pierre';

                public function anonyme(){
                    return new class($this->age) extends Externe{
                        private $a;
                        private $n;
                    
                        public function __construct($age){
                            $this->a = $age;
                        }
                        public function getNomAge(){
                            return 'Nom : ' .$this->nom. ', âge : ' .$this->a;
                        }
                    };
                }
            }
            
            $obj = new Externe;
            echo $obj->anonyme()->getNomAge();
        ?>
        <p>Un paragraphe</p>
    </body>
</html>

 

Création et utilisation d'une classe anonyme en PHP

Ici, on déclare une première classe nommée Externe qui contient une propriété privée $age et une propriété protégée $nom.

Notre classe Externe contient également une méthode qui retourne une classe anonyme. On va vouloir utiliser les propriétés de code>Externe dans la classe anonyme. Pour cela, on passe notre variable protégée dans la définition de la classe et dans le constructeur.

Cette leçon et ce dernier exemple en particulier doivent vous sembler plus difficile à appréhender que le reste jusqu’ici. Pas d’inquiétude, c’est tout à fait normal car on commence à toucher à des notions vraiment avancées et il n’est pas simple d’en montrer l’intérêt à travers des exemples simples.

En pratique, je vous rassure, vous n’aurez que très rarement à faire ce genre de choses ou même à utiliser les classes anonymes.

Cependant, utiliser des classes anonymes peut s’avérer très pratique dans certaines situations et je dois donc vous présenter ce qu’il st possible de faire avec elles aujourd’hui en POO PHP.

Laisser un commentaire