PHP 5.3 : LSB : Late Static Binding

27 octobre 2008php, php-5.3, static
 Cet article a été rédigé il y a plusieurs années et peut ne plus être tout à fait à jour…

Les exemples correspondant à ce point se trouvent dans le répertoire "late-static-binding".

PHP 5.3 introduit la notion "Late Static Binding" : tout ce qui est "statique" peut désormais être lié à l'exécution, et non plus à la compilation !

Sommaire :


PHP 5.2 : Pas de Late Static Binding

Pour cadrer un peu les choses, je pense qu'il peut être judicieux de commencer par un exemple en PHP 5.2, illustrant le manque de LSB, et les problématiques posées.

Imaginons la classe Vehicule, définie de la manière suivante :

class Vehicule {
    public static function a() {
        echo '<pre>' . __CLASS__ . '</pre>';    // Etape 3
    }
    public static function b() {
        self::a();   // Etape 2 : PHP 5.2 => "self"
    }
}

Et la classe Voiture, qui défini un type spécifique de Vehicule, et hérite donc de la première classe :

class Voiture extends Vehicule {
    public static function a() {
        echo '<pre>' . __CLASS__ . '</pre>';
    }
}

Ces deux classes définissent toutes deux une méthode statique[1], nommée a.
La classe-mère, quand à elle, défini en plus une seconde méthode statique, nommée b, dont la classe Voiture hérite.

Appelons cette méthode b, statiquement, en passant par la classe fille :

Voiture::b(); // Etape 1

Les appels se font en trois étapes :

  • Nous appelons la méthode b, définie dans la classe-mère Vehicule, via la classe-fille Voiture
  • Nous passons dans le corps de la méthode Vehicule::b, qui fait appel à la méthode self::a
  • PHP 5.2 ne fonctionne pas selon un mode tardif de résolution des données statiques ;
    • Cela signifie que self correspond à la classe au sein de laquelle self est utilisé... Ici, self correspond donc à Vehicule (et non à Voiture)
    • La méthode qui est appelée ensuite, via self::a, est donc Vehicule::a, et non Voiture::a
    • Et ce alors que nous avions commencé en appelant une méthode de la classe Voiture !

Et le résultat final est l'affichage suivant :

Vehicule

Comme dit plus haut, le mot-clef self désigne la classe au sein de laquelle il est utilisé ; ici, il s'agit de la classe Vehicule ; c'est dont la méthode Vehicule::a qui a été finalement exécutée.


PHP 5.3 : Late State Binding

En réponse à cette limitation, à cause de laquelle jouer avec des méthodes et variables statiques en même temps que l'on travaille avec des classes héritant les unes des autres est particulièrement risqué en PHP <= 5.2, PHP 5.3 introduit la notion de "Late Static Binding".
Voyons ce qu'elle nous permet...

Pour commencer, voici une version révisée de notre classe Vehicule, conçue pour tirer parti du LSB :

class Vehicule {
    public static function a() {
        echo '<pre>' . __CLASS__ . '</pre>';
    }
    public static function b() {
        static::a();   // Etape 2 : PHP 5.3 LSB => "static"
    }
}

La seule différence avec la version utilisée plus haut est l'emploi du mot-clef static à la place du mot-clef self lors de l'appel de la méthode a.

La classe Voiture, quant à elle, demeure définie de la même manière :

class Voiture extends Vehicule {
    public static function a() {
        echo '<pre>' . __CLASS__ . '</pre>';    // Etape 3
    }
}

Et l'appel utilisé pour notre est toujours le même, passant par la classe Voiture :

Voiture::b(); // Etape 1

Qu'obtenons-nous cette fois-ci ?
Ici encore, les appels se font en trois étapes :

  • Nous appelons la méthode b, définie dans la classe-mère Vehicule, via la classe-fille Voiture
  • Nous passons dans le corps de la méthode Vehicule::b, qui fait appel à la méthode static::a
  • PHP 5.3 peut fonctionner selon un mode tardif de résolution des données statiques ;
    • Le mot-clef static, utilisé pour la résolution de classe, correspond à la classe appelée, et non à celle au sein de laquelle il est utilisé... Contrairement à self. Ici, static correspond donc à Voiture
    • La méthode qui est appelée ensuite, via static::a, est donc Voiture::a
    • Ce qui semble plus logique, puisque nous avions commencé par un appel à Voiture::b !

Finalement, nous obtiendrons l'affichage suivant :

Voiture

Globalement, le Late Static Binding combiné à l'utilisation du mot-clef static recyclé, permettent enfin de travailler de manière logique avec des méthodes statiques dans un contexte d'héritages.


Conserver le fonctionnement de PHP 5.2 en PHP 5.3

Cela dit, pour des raisons écidentes de compatibilité et de non cassage de code existant, le LSB ne change pas le fonctionnement qui était existant en PHP 5.2 !

Autrement dit, l'utilisation du mot-clef self en PHP 5.3 donnera exactement le même type de comportement, et de résultats, que ce à quoi nous étions habitué en PHP <= 5.2 !


Note

[1] Le fait que la méthode définie dans les deux classes soit statique est le point important ici !