La résolution statique à la volée ou late static bindings en PHP

Télécharger le PDF du cours


Livret PDF du cours PHP et MySQL
Dans cette nouvelle leçon, nous allons découvrir une fonctionnalité très intéressante du PHP appelée la résolution statique à la volée ou « late static binding » en anglais et comprendre les problèmes qu’elle résout.

 

Définition et intérêt de la résolution statique à la volée

La résolution statique à la volée va nous permettre de faire référence à la classe réellement appelée dans un contexte d’héritage statique.

En effet, lorsqu’on utilise le self:: pour faire référence à la classe courante dans un contexte statique, la classe utilisée sera toujours celle dans laquelle sont définies les méthodes utilisant self::.

Cela peut parfois produire des comportements inattendus. Regardez plutôt l’exemple ci-dessous pour vous en convaincre.

<?php
    abstract class Utilisateur{
        protected $user_name;
        protected $user_region;
        protected $prix_abo;
        protected $user_pass;
        protected $x = 0;
        public const ABONNEMENT = 15;
        
        public function __construct($n, $p, $r){
            $this->user_name = $n;
            $this->user_pass = $p;
            $this->user_region = $r;
        }
        public function __destruct(){
            //Du code à exécuter
        }
        
        public static function getStatut(){
            self::statut();
        }
        public static function statut(){
            echo 'Utilisateur';
        }
        
        public function getNom(){
            echo $this->user_name;
        }

        public function getPrixAbo(){
            echo $this->prix_abo;
        }
        abstract public function setPrixAbo();
    }
?>

 

<?php
    class Admin extends Utilisateur{
        protected static $ban;
        
        public function __construct($n, $p, $r){
            $this->user_name = strtoupper($n);
            $this->user_pass = $p;
            $this->user_region = $r;
        }
        
        public static function statut(){
            echo 'Admin';
        }
        
        public function getNom(){
            echo $this->user_name. '(Admin)';
        }
        
        public function setBan(...$b){
            foreach($b as $banned){
                self::$ban[] .= $banned;
            }
        }
        public function getBan(){
            echo 'Utilisateurs bannis : ';
            foreach(self::$ban as $valeur){
                echo $valeur .', ';
            }
        }
        
        public function setPrixAbo(){
            if($this->user_region === 'Sud'){
                return $this->prix_abo = parent::ABONNEMENT / 6;
            }else{
                return $this->prix_abo = parent::ABONNEMENT / 3;
            }
        }
    }
?>

 

<!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
            spl_autoload_register(function($classe){
                require 'classes/' .$classe. '.class.php';
            });
            
            /*On n'a pas besoin d'instancier nos classes ici puisqu'on se contente
             *d'utiliser une méthode statique (= qui appartient à la classe)*/
            Admin::getStatut();
        ?>
        <p>Un paragraphe</p>
    </body>
</html>

 

Exemple illustrant les problèmes de comportement liés à self en PHP objet

Ici, on réutilise nos classes Utilisateur (classe mère) et Admin (classe étendue). Dans notre classe Utilisateur, on définit deux méthodes statiques getStatut() et statut().

La méthode statut() de la classe Utilisateur renvoie le mot « Utilisateur ». La méthode getStatut() sert elle a exécuter la méthode statut() de la classe courante.

On surcharge ensuite notre méthode statut() dans notre classe étendue Admin afin qu’elle renvoie le texte « Admin ».

Finalement, dans notre script principal, on appelle notre méthode getStatut() depuis notre classe Admin.

Comme vous pouvez le voir, le résultat renvoyé est « Utilisateur » et non pas « Admin » comme on aurait pu le penser instinctivement. Cela est dû au fait que le code self:: dans notre méthode getStatut() va toujours faire référence à la classe dans laquelle la méthode a été définie, c’est-à-dire la classe Utilisateur.

Ainsi, self::statut() sera toujours l’équivalent de Utilisateur::statut() et renverra toujours la valeur de la méthode statut() définie dans la classe Utilisateur.

La résolution statique à la volée a été introduite justement pour dépasser ce problème précis et pour pouvoir faire référence à la classe réellement utilisée.

 

Utilisation de la résolution statique à la volée et de static::

La résolution statique à la volée va donc nous permettre de faire référence à la classe réellement utilisée dans un contexte statique.

Pour utiliser la résolution statique à la volée, nous allons simplement devoir utiliser le mot clef static à la place de self. Ce mot clef va nous permettre de faire référence à la classe utilisée durant l’exécution de notre méthode.

Reprenons l’exemple précédent et changeons self:: par static:: dans le code de notre méthode getStatut().

<?php
    abstract class Utilisateur{
        protected $user_name;
        protected $user_region;
        protected $prix_abo;
        protected $user_pass;
        protected $x = 0;
        public const ABONNEMENT = 15;
        
        public function __construct($n, $p, $r){
            $this->user_name = $n;
            $this->user_pass = $p;
            $this->user_region = $r;
        }
        public function __destruct(){
            //Du code à exécuter
        }
        
        public static function getStatut(){
            static::statut();
        }
        public static function statut(){
            echo 'Utilisateur';
        }
        
        public function getNom(){
            echo $this->user_name;
        }

        public function getPrixAbo(){
            echo $this->prix_abo;
        }
        abstract public function setPrixAbo();
    }
?>

 

Exemple de résolution statique à la volée ou late static bindings en PHP objet

Cette fois-ci, la méthode getStatut() va exécuter la méthode statut() de la classe utilisée, c’est-à-dire de la classe Admin et c’est donc la valeur « Admin » qui va être renvoyée.

Laisser un commentaire