Depuis PHP 5.3.0, PHP implémente une fonctionnalité appelée late static binding, en français la résolution statique à la volée, qui est utilisée pour choisir la classe appelée dans le cadre de l'héritage de méthodes statiques.
Plus précisément, les résolutions statiques à la volée fonctionnent en enregistrant le nom de le classe dans le dernier "appel non transmis". Dans le cas des appels de méthodes statiques, il s'agit de la classe explicitement nommée à gauche de l'opérateur ::; dans le cas de méthodes non statiques, il s'agit de la classe de l'objet. Un "appel transmis" est déclenché par self::, parent::, static::, ou, tout en haut de la hierarchie des classes, forward_static_call(). La fonction get_called_class() peut être utilisée pour récupérer une chaine contenant le nom de la classe appelée et static:: introduit son espace.
Cette fonctionnalité a été baptisée "late static bindings", d'un point de vue interne. "Late binding", littéralement compilation tardive, vient du fait que les éléments static:: ne seront pas résolus en utilisant la classe où la méthode a été définie, mais celle qui est active durant l'exécution. L'adjectif statique a été ajouté car ce problème s'applique aux méthodes statiques, mais pas seulement.
Les références à la classe courante, avec self:: ou __CLASS__ sont résolues en utilisant la classe à qui appartiennent les fonctions, où elles ont été définies :
Exemple #1 Utilisation de self::
<?php
class A {
public static function qui() {
echo __CLASS__;
}
public static function test() {
self::qui();
}
}
class B extends A {
public static function qui() {
echo __CLASS__;
}
}
B::test();
?>
L'exemple ci-dessus va afficher :
A
La résolution statique à la volée essaie de dépasser cette limitation en introduisant un mot clé qui fait référence à la classe qui est appelée durant l'exécution. Simplement, ce mot-clé vous permet de faire référence à B depuis test(), dans l'exemple précédent. Il a été décidé de ne pas introduire de nouveau mot clé, mais plutôt d'utiliser le mot static qui était déjà réservé.
Exemple #2 Utilisation simple de static::
<?php
class A {
public static function qui() {
echo __CLASS__;
}
public static function test() {
static::qui(); // Ici, résolution à la volée
}
}
class B extends A {
public static function qui() {
echo __CLASS__;
}
}
B::test();
?>
L'exemple ci-dessus va afficher :
B
Note:
Notez que dans les contextes non statiques, la classe appelée sera la même que la classe de l'objet. Comme $this-> essayera d'appeler des méthodes privées depuis le même contexte, utiliser static:: pourrait donner des résultats différents. Notez aussi que static:: ne peut faire référence qu'à des attributs/méthodes statiques.
Exemple #3 Utilisation de static:: dans un contexte non statique
<?php
class A {
private function foo() {
echo "success!\n";
}
public function test() {
$this->foo();
static::foo();
}
}
class B extends A {
/* foo() sera copiée dans B, par conséquent son contexte sera toujours A
* et l'appel se fera sans problème */
}
class C extends A {
private function foo() {
/* La méthode originale est remplacée; le contexte est celui de C */
}
}
$b = new B();
$b->test();
$c = new C();
$c->test(); //échoue
?>
L'exemple ci-dessus va afficher :
success! success! success! Fatal error: Call to private method C::foo() from context 'A' in /tmp/test.php on line 9
Note:
La résolution des statiques à la volée va s'arrêter à un appel statique complètement résolu. D'un autre coté, les appels statiques en utilisant un mot-clé comme parent:: ou self:: va transmettre l'information appelante.
Exemple #4 Appel avec ou sans transmission
<?php
class A {
public static function foo() {
static::qui();
}
public static function qui() {
echo __CLASS__."\n";
}
}
class B extends A {
public static function test() {
A::foo();
parent::foo();
self::foo();
}
public static function qui() {
echo __CLASS__."\n";
}
}
class C extends B {
public static function qui() {
echo __CLASS__."\n";
}
}
C::test();
?>L'exemple ci-dessus va afficher :
A C C