Que sont exactement les liaisons statiques tardives en PHP?
Vous devez absolument lire Liaisons statiques tardives dans le manuel PHP. Cependant, je vais essayer de vous donner un bref résumé.
Fondamentalement, cela se résume au fait que le mot clé self
ne suit pas les mêmes règles d'héritage. self
résout toujours la classe dans laquelle il est utilisé. Cela signifie que si vous créez une méthode dans une classe parent et l'appelez à partir d'une classe enfant, self
ne référencera pas l'enfant comme vous pouvez vous y attendre.
La liaison statique tardive introduit une nouvelle utilisation du mot clé static
, qui corrige cette lacune particulière. Lorsque vous utilisez static
, il représente la classe où vous l'utilisez pour la première fois, c'est-à-dire. il "se lie" à la classe d'exécution.
Ce sont les deux concepts de base derrière cela. La façon dont self
, parent
et static
fonctionnent lorsque static
est en jeu peut être subtile, plutôt que d'aller plus en détail, je serais fortement vous recommandons d'étudier les exemples de page de manuel. Une fois que vous avez compris les bases de chaque mot-clé, les exemples sont tout à fait nécessaires pour voir quel type de résultats vous obtiendrez.
À partir de PHP 5.3.0, PHP implémente une fonctionnalité appelée liaison statique tardive qui peut être utilisée pour référencer la classe appelée dans le contexte de l'héritage statique).
La liaison statique tardive tente de résoudre cette limitation en introduisant un mot clé qui fait référence à la classe qui a été initialement appelée lors de l'exécution. Il a été décidé de ne pas introduire un nouveau mot-clé, mais plutôt d'utiliser static
qui était déjà réservé.
Voyons un exemple:
<?php
class Car
{
public static function run()
{
return static::getName();
}
private static function getName()
{
return 'Car';
}
}
class Toyota extends Car
{
public static function getName()
{
return 'Toyota';
}
}
echo Car::run(); // Output: Car
echo Toyota::run(); // Output: Toyota
?>
late static bindings
Fonctionne en stockant la classe nommée dans le dernier "appel sans renvoi". Dans le cas d'appels de méthode statiques, il s'agit de la classe nommée explicitement (généralement celle à gauche de l'opérateur ::); en cas d'appels de méthode non statiques, c'est la classe de l'objet.
Un "appel de transfert" est un appel statique qui est introduit par self::
, parent::
, static::
, Ou, s'il monte dans la hiérarchie des classes, forward_static_call()
.
La fonction get_called_class()
peut être utilisée pour récupérer une chaîne avec le nom de la classe appelée et static::
Introduit sa portée.
Il n'y a pas de comportement très évident:
Le code suivant produit 'alphabeta'.
class alpha {
function classname(){
return __CLASS__;
}
function selfname(){
return self::classname();
}
function staticname(){
return static::classname();
}
}
class beta extends alpha {
function classname(){
return __CLASS__;
}
}
$beta = new beta();
echo $beta->selfname(); // Output: alpha
echo $beta->staticname(); // Output: beta
Cependant, si nous supprimons la déclaration de la fonction classname de la classe beta, nous obtenons 'alphaalpha' comme résultat.
Je cite le livre: "PHP Master écrit du code de pointe".
La liaison statique tardive a été introduite avec php 5.3. Il nous permet d'hériter des méthodes statiques d'une classe parente et de référencer la classe enfant appelée.
Cela signifie que vous pouvez avoir une classe abstraite avec des méthodes statiques et référencer les implémentations concrètes de la classe enfant en utilisant la notation static :: method () au lieu de self :: method ().
N'hésitez pas à jeter un œil à la documentation officielle de php: http://php.net/manual/en/language.oop5.late-static-bindings.php
La manière la plus claire d'expliquer la liaison statique tardive consiste à utiliser un exemple simple. Jetez un œil aux deux définitions de classe ci-dessous et continuez à lire.
class Vehicle {
public static function invokeDriveByStatic() {
return static::drive(); // Late Static Binding
}
public static function invokeStopBySelf() {
return self::stop(); // NOT Late Static Binding
}
private static function drive(){
return "I'm driving a vehicle";
}
private static function stop(){
return "I'm stopping a vehicle";
}
}
class Car extends Vehicle {
protected static function drive(){
return "I'm driving a CAR";
}
private static function stop(){
return "I'm stopping a CAR";
}
}
Nous voyons une classe parent (véhicule) et une classe enfant (voiture). La classe parent a 2 méthodes publiques:
invokeDriveByStatic
invokeStopBySelf
La classe parent a également 2 méthodes privées:
drive
stop
La classe enfant remplace 2 méthodes:
drive
stop
Appelons maintenant les méthodes publiques:
invokeDriveByStatic
invokeStopBySelf
Demandez-vous: quelle classe invoque invokeDriveByStatic
/invokeStopBySelf
? La classe Parent ou Enfant?
Jetez un œil ci-dessous:
// This is NOT Late Static Binding
// Parent class invokes from Parent. In this case Vehicle.
echo Vehicle::invokeDriveByStatic(); // I'm driving a vehicle
echo Vehicle::invokeStopBySelf(); // I'm stopping a vehicle
// This is Late Static Binding.
// Child class invokes an inherited method from Parent.
// Child class = Car, Inherited method = invokeDriveByStatic().
// ...
// The inherited method invokes a method that is overridden by the Child class.
// Overridden method = drive()
echo Car::invokeDriveByStatic(); // I'm driving a CAR
// This is NOT Late Static Binding
// Child class invokes an inherited method from Parent.
// The inherited method invokes a method inside the Vehicle context.
echo Car::invokeStopBySelf(); // I'm stopping a vehicle
Le mot clé static
est utilisé dans un modèle de conception Singleton. Voir le lien: https://refactoring.guru/design-patterns/singleton/php/example
L'exemple le plus simple pour montrer la différence.
Remarque, self :: $ c
class A
{
static $c = 7;
public static function getVal()
{
return self::$c;
}
}
class B extends A
{
static $c = 8;
}
B::getVal(); // 7
Liaison statique tardive, remarque static :: $ c
class A
{
static $c = 7;
public static function getVal()
{
return static::$c;
}
}
class B extends A
{
static $c = 8;
}
B::getVal(); // 8
En le regardant d'un "pourquoi devrais-je utiliser cela?" perspective, c'est essentiellement un moyen de changer le contexte à partir duquel la méthode statique est interprétée/exécutée.
Avec self
, le contexte est celui où vous avez défini la méthode à l'origine. Avec static
, c'est celui à partir duquel vous l'appelez.
Par exemple:
abstract class Builder {
public static function build() {
return new static;
}
}
class Member extends Builder {
public function who_am_i() {
echo 'Member';
}
}
Member::build()->who_am_i();
Vérifiez également si vous mettez à jour des variables statiques dans les classes enfants. J'ai trouvé ce résultat (quelque peu) inattendu où l'enfant B met à jour l'enfant C:
class A{
protected static $things;
}
class B extends A {
public static function things(){
static::$things[1] = 'Thing B';
return static::$things;
}
}
class C extends A{
public static function things(){
static::$things[2] = 'Thing C';
return static::$things;
}
}
print_r(C::things());
// Array (
// [2] => Thing C
// )
B::things();
print_r(C::things());
// Array (
// [2] => Thing C
// [1] => Thing B
// )
Vous pouvez le corriger en déclarant la même variable dans chaque classe enfant, par exemple:
class C extends A{
protected static $things; // add this and B will not interfere!
public static function things(){
static::$things[2] = 'Thing C';
return static::$things;
}
}