La résolution statique à la volée ou Late Static Bindings

La résolution tardive pour renforcer le principe d'héritage

Depuis PHP 5.3, le langage implémente une fonctionnalité nommée "résolution statique à la volée" ou en anglais "late static bindings". Cette fonctionnalité permet de mieux résoudre les appels des méthodes statiques.

Pour mieux comprendre, voici un exemple : je possède une bibliothèque de jeux (échecs, dames, petits chevaux etc...) qui ont tous un plateau. Naturellement je ne souhaite pas ré-implémenter dans toutes mes classes les parties de code qui peuvent être en commun, j'aurai donc une classe mère Plateau dont hériteront tous mes plateaux. Un plateau de jeu est quelque chose d'unique dans une partie, il serait fort dommage de créer un deuxième plateau en pleine partie d'échecs. Tous mes plateaux seront donc des Singleton.

Sans le late static bindings, l'erreur courante

Utilisation de get_class, __CLASS__ ou self

class Plateau { protected static $_oInstance = null; protected function __construct() { echo "Je suis la classe mere."; } public static function getInstance() { // Faites votre choix entre return (self::$_oInstance ?: (self::$_oInstance = new self)); // OU $sClasseNom = __CLASS__; return (self::$_oInstance ?: (self::$_oInstance = new $sClasseNom)); // OU $sClasseNom = get_class(); return (self::$_oInstance ?: (self::$_oInstance = new $sClasseNom)); } } class PlateauEchec extends Plateau { protected function __construct() { echo "Je suis le plateau d'echec."; } } $plateau = PlateauEchec::getInstance(); /* Affichage : Je suis la classe mere. */ echo get_class($plateau); /* Affichage : Plateau */

Et oui ! Lors de la résolution, PHP a instancié la mauvaise classe. En pratique la classe Plateau devrait même être déclarée abstraite, ce qui nous aurait valu une jolie erreur.

Avec le late static bindings

Utilisation de get_called_class ou static

class Plateau { protected static $_oInstance = null; protected function __construct() { echo "Je suis la classe mere."; } public static function getInstance() { // Faites votre choix entre return (self::$_oInstance ?: (self::$_oInstance = new static)); // OU $sClasseNom = get_called_class(); return (self::$_oInstance ?: (self::$_oInstance = new $sClasseNom)); } } class PlateauEchec extends Plateau { protected function __construct() { echo "Je suis le plateau d'echec."; } } $plateau = PlateauEchec::getInstance(); /* Affichage : Je suis le plateau d'echec. */ echo get_class($plateau); /* Affichage : PlateauEchec */

Le mot clé static permet, dans cette situation, de résoudre la classe appelante lors de l'exécution. Malgré son nom, le Late Static Bindings n'est pas un phénomène réservé aux méthodes déclarée statiques, j'ai eu pour ma part, par exemple, quelques surprises en utilisant la réflexivité. Mais ceci fera l'objet d'un prochain tutoriel.