web-dev-qa-db-fra.com

Que sont exactement les liaisons statiques tardives en PHP?

Que sont exactement les liaisons statiques tardives en PHP?

123
Sarfraz

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.

185
zombat

À 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.

79
Mrinmoy Ghoshal

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.

22
Jokerius

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

10
Julian

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
7
Sergey Onishchenko

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.

4
DanMan

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

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