Que sont exactement les liaisons statiques tardives en PHP?

Réponses:

198

Vous devez absolument lire les liaisons statiques tardives dans le manuel PHP. Cependant, je vais essayer de vous donner un bref résumé.

En gros, cela se résume au fait que le selfmot-clé ne suit pas les mêmes règles d'héritage. selfrésout toujours la classe dans laquelle il est utilisé. Cela signifie que si vous créez une méthode dans une classe parent et que vous l'appelez à partir d'une classe enfant, vous selfne référencerez pas l'enfant comme vous vous en doutez.

La liaison statique tardive introduit une nouvelle utilisation du staticmot - clé, qui résout 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 self, parentet staticfonctionne quand staticest en jeu peut être subtile, alors plutôt que d' aller pour plus de détails, je vous recommande fortement que vous étudiez les exemples de pages de manuel. Une fois que vous avez compris les bases de chaque mot-clé, les exemples sont tout à fait nécessaires pour voir le type de résultats que vous allez obtenir.

zombat
la source
J'ai trouvé cet article vraiment utile et descriptif, consultez-le [lien] ( techflirt.com/tutorials/oop-in-php/late-static-binding.html )
Sadegh Shaikhi
"... le selfmot-clé ne suit pas les règles d'héritage. selfrésout toujours la classe dans laquelle il est utilisé." - Ce qui ne signifie pas que vous ne pouvez pas appeler la méthode statique d'un parent à partir d'un objet enfant via self, comme avec les méthodes non statiques. Vous pensez peut-être la bonne chose, mais vous devriez reformuler cela. Tout cela n'a vraiment d'importance qu'une fois que les enfants ont des membres nommés de manière identique, car vous pouvez ensuite décider à ceux auxquels vous référer en utilisant à la static::place.
DanMan
81

Depuis PHP: liaisons statiques tardives - Manuel :

Depuis 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 initialement appelée au moment de l'exécution. ... Il a été décidé de ne pas introduire de nouveau mot-clé, mais plutôt d'utiliser staticqui é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
?>

Les liaisons statiques tardives fonctionnent en stockant la classe nommée dans le dernier "appel sans transfert". En cas d'appels de méthodes statiques, il s'agit de la classe explicitement nommée (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 une statique qui est introduit par self::, parent::, static::ou, si vous allez 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.

Mrinmoy Ghoshal
la source
1
Ce message est à ~ 80% une copie textuelle de l' article de php.net sans marqueurs de citation.
WoodrowShigeru
22

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.

Jokerius
la source
1
Très agréable. La même chose est montrée dans le manuel PHP, mais c'est beaucoup plus clair. Pour référence: php.net/manual/en/language.oop5.late-static-bindings.php (voir ex.4 )
musicin3d
11

Je cite le livre: "PHP Master écrit du code de pointe".

La liaison statique tardive était une fonctionnalité introduite avec php 5.3. Cela nous permet d'hériter des méthodes statiques d'une classe parent 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 à consulter également 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 est d'utiliser un exemple simple. Jetez un œil aux deux définitions de classe ci-dessous et poursuivez votre lecture.

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 dispose également de 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 staticmot-clé est utilisé dans un modèle de conception Singleton. Voir le lien: https://refactoring.guru/design-patterns/singleton/php/example

julien
la source
7

L'exemple le plus simple pour montrer la différence.
Remarque, soi - même :: $ 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, notez static :: $ c

class A
{
    static $c = 7;

    public static function getVal()
    {
        return static::$c;
    }
}

class B extends A
{
    static $c = 8;
}

B::getVal(); // 8
Sergey Onishchenko
la source
4

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();
Petah
la source
4

En le regardant à partir d'un "pourquoi est-ce que j'utiliserais ceci?" 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 dans lequel vous avez défini la méthode à l'origine. Avec static, c'est celui d'où vous l'appelez.

DanMan
la source
1

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;        
    }
}
Frank Forte
la source