Was genau sind späte statische Bindungen in PHP?

Antworten:

197

Sie müssen unbedingt Late Static Bindings im PHP-Handbuch lesen . Ich werde jedoch versuchen, Ihnen eine kurze Zusammenfassung zu geben.

Grundsätzlich selfläuft es darauf hinaus, dass das Schlüsselwort nicht denselben Vererbungsregeln folgt. selfwird immer in die Klasse aufgelöst, in der es verwendet wird. Dies bedeutet, dass, wenn Sie eine Methode in einer übergeordneten Klasse erstellen und von einer untergeordneten Klasse aus aufrufen, selfdas untergeordnete Element nicht wie erwartet referenziert wird.

Durch die späte statische Bindung wird eine neue Verwendung für das staticSchlüsselwort eingeführt, mit der dieses spezielle Manko behoben wird. Wenn Sie verwenden static, stellt es die Klasse dar, in der Sie es zuerst verwenden, d. H. es 'bindet' an die Laufzeitklasse.

Das sind die beiden Grundkonzepte dahinter. Die Art und Weise self, parentund staticarbeitet , wenn staticim Spiel ist subtil sein kann, so anstatt zu gehen, um Details, würde ich empfehlen , dass Sie die Manpage Beispiele zu studieren. Sobald Sie die Grundlagen der einzelnen Keywords verstanden haben, sind die Beispiele sehr wichtig, um zu sehen, welche Ergebnisse Sie erzielen werden.

Zombat
quelle
Ich fand diesen Artikel wirklich nützlich und beschreibend. Schauen Sie sich [Link] an ( techflirt.com/tutorials/oop-in-php/late-static-binding.html )
Sadegh Shaikhi
"... das selfSchlüsselwort folgt nicht den Vererbungsregeln. Es wird selfimmer in die Klasse aufgelöst, in der es verwendet wird." - Das bedeutet nicht, dass Sie die statische Methode eines Elternteils nicht selfwie bei nicht statischen Methoden von einem untergeordneten Objekt aus aufrufen können. Sie meinen vielleicht das Richtige, aber Sie sollten das umformulieren. Es ist alles nur dann wirklich wichtig, wenn Kinder identisch benannte Mitglieder haben, da Sie dann entscheiden können, auf welche Mitglieder Sie sich beziehen möchten, indem Sie static::stattdessen verwenden.
DanMan
81

Von PHP: Late Static Bindings - Handbuch :

Ab PHP 5.3.0 implementiert PHP eine Funktion namens Late Static Binding, mit der die aufgerufene Klasse im Kontext der statischen Vererbung referenziert werden kann.

Die späte statische Bindung versucht, diese Einschränkung zu lösen, indem ein Schlüsselwort eingeführt wird, das auf die Klasse verweist, die ursprünglich zur Laufzeit aufgerufen wurde. ... Es wurde beschlossen, kein neues Schlüsselwort einzuführen, sondern staticdas bereits reservierte zu verwenden.

Sehen wir uns ein Beispiel an:

<?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
?>

Späte statische Bindungen speichern die im letzten "Nicht-Weiterleitungsaufruf" genannte Klasse. Bei statischen Methodenaufrufen ist dies die explizit benannte Klasse (normalerweise die links vom ::Operator). Bei nicht statischen Methodenaufrufen ist dies die Klasse des Objekts. Eine „Anrufweiterschaltung“ ist ein statischer , die durch eingeführt wird self::, parent::, static::oder, wenn in der Klassenhierarchie steigen, forward_static_call(). Die Funktion get_called_class()kann verwendet werden, um eine Zeichenfolge mit dem Namen der aufgerufenen Klasse abzurufen und static::ihren Gültigkeitsbereich einzuführen.

Mrinmoy Ghoshal
quelle
1
Dieser Beitrag ist zu ~ 80% eine wörtliche Kopie des php.net-Artikels ohne Zitiermarker .
WoodrowShigeru
22

Es gibt kein sehr offensichtliches Verhalten:

Der folgende Code erzeugt '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

Wenn wir jedoch die Deklaration der Klassennamenfunktion aus der Beta-Klasse entfernen, erhalten wir als Ergebnis 'alphaalpha'.

Jokerius
quelle
1
Sehr schön. Das gleiche wird im PHP-Handbuch gezeigt, aber das ist viel klarer. Als Referenz: php.net/manual/en/language.oop5.late-static-bindings.php (siehe Bsp. 4)
musicin3d
11

Ich zitiere aus dem Buch: "PHP Master schreibt topaktuellen Code".

Die späte statische Bindung war ein Merkmal, das mit PHP 5.3 eingeführt wurde. Es ermöglicht uns, statische Methoden von einer übergeordneten Klasse zu erben und auf die aufgerufene untergeordnete Klasse zu verweisen.

Dies bedeutet, dass Sie eine abstrakte Klasse mit statischen Methoden haben und auf die konkreten Implementierungen der untergeordneten Klasse verweisen können, indem Sie die Notation static :: method () anstelle der Notation self :: method () verwenden.

Schauen Sie sich auch die offizielle PHP-Dokumentation an: http://php.net/manual/en/language.oop5.late-static-bindings.php


Die Erklärung der späten statischen Bindung lässt sich am einfachsten anhand eines einfachen Beispiels erklären. Schauen Sie sich die beiden folgenden Klassendefinitionen an und lesen Sie weiter.

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";
    }
}

Wir sehen eine Elternklasse (Fahrzeug) und eine Kinderklasse (Auto). Die Elternklasse verfügt über zwei öffentliche Methoden:

  • invokeDriveByStatic
  • invokeStopBySelf

Die Elternklasse hat auch zwei private Methoden:

  • drive
  • stop

Die untergeordnete Klasse überschreibt zwei Methoden:

  • drive
  • stop

Rufen wir nun die öffentlichen Methoden auf:

  • invokeDriveByStatic
  • invokeStopBySelf

Fragen Sie sich: Welche Klasse ruft invokeDriveByStatic/ auf invokeStopBySelf? Die Eltern- oder Kinderklasse?

Schauen Sie unten nach:

// 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

Das staticSchlüsselwort wird in einem Singleton-Entwurfsmuster verwendet. Siehe Link: https://refactoring.guru/design-patterns/singleton/php/example

Julian
quelle
7

Das einfachste Beispiel, um den Unterschied zu zeigen.
Beachten Sie, self :: $ c

class A
{
    static $c = 7;

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

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

B::getVal(); // 7

Späte statische Bindung, beachten Sie 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
quelle
4

Beispielsweise:

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
quelle
4

Betrachten Sie es aus einem "Warum sollte ich das verwenden?" Perspektive ist es im Grunde eine Möglichkeit, den Kontext zu ändern, aus dem die statische Methode interpretiert / ausgeführt wird.

Mit selfist der Kontext derjenige, in dem Sie die Methode ursprünglich definiert haben. Mit static, es ist das, von dem Sie es anrufen.

DanMan
quelle
1

Beobachten Sie auch, ob Sie statische Variablen in untergeordneten Klassen aktualisieren. Ich fand dieses (etwas) unerwartete Ergebnis, bei dem Kind B Kind C aktualisiert:

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
// )

Sie können das Problem beheben, indem Sie in jeder untergeordneten Klasse dieselbe Variable deklarieren. Beispiel:

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
quelle