Late Static Bindings

Оновлено: 12.05.2023

PHP реалізує функцію пізнього статичного зв'язування, яка може бути використана для посилання на клас, що викликається, в контексті статичного успадкування.

Точніше кажучи, пізні статичні зв'язування працюють, зберігаючи клас, названий в останньому "непереадресованому виклику". У випадку статичних викликів методів, це клас, який явно названо (зазвичай той, що стоїть зліва від оператора ::); у випадку нестатичних викликів методів, це клас об'єкта. "Переадресований виклик" - це статичний виклик, який вводиться за допомогою self::, parent::, static::, або, якщо підніматися вище в ієрархії класів, forward_static_call(). Функція get_called_class() може бути використана для отримання рядка з іменем викликаного класу, а static:: вводить його область видимості.

Цю можливість було названо "пізнім статичним зв'язуванням" з огляду на внутрішню перспективу. "Пізнє зв'язування" походить від того факту, що static:: не буде розв'язано за допомогою класу, в якому визначено метод, а буде обчислено за допомогою інформації, отриманої під час виконання програми. Його також називають "статичним зв'язуванням", оскільки його можна використовувати для (але не обмежуючись) статичних викликів методів.

Статичні посилання на поточний клас, такі як self:: або __CLASS__, обробляються за допомогою класу, до якого належить функція, тобто там, де вона була визначена:

Приклад #1 self:: використання

<?php
class A {
    public static function who() {
        echo __CLASS__;
    }
    public static function test() {
        self::who();
    }
}

class B extends A {
    public static function who() {
        echo __CLASS__;
    }
}

B::test();
?>

Пізнє статичне зв'язування намагається вирішити це обмеження шляхом введення ключового слова, яке посилається на клас, що був викликаний під час виконання. По суті, це ключове слово, яке дозволило б посилатися на B з test() у попередньому прикладі. Було вирішено не вводити нове ключове слово, а використати вже зарезервоване static.

Приклад #2 статичний:: просте використання

<?php
class A {
    public static function who() {
        echo __CLASS__;
    }
    public static function test() {
        static::who(); // Here comes Late Static Bindings
    }
}

class B extends A {
    public static function who() {
        echo __CLASS__;
    }
}

B::test();
?>

Зауважте:

У нестатичних контекстах клас, що викликається, буде класом екземпляра об'єкта. Оскільки $this-> намагатиметься викликати приватні методи з тієї самої області видимості, використання static:: може призвести до різних результатів. Інша відмінність полягає в тому, що static:: може посилатися тільки на статичні властивості.

Приклад #3 static:: використання в нестатичному контексті

<?php
class A {
    private function foo() {
        echo "success!\n";
    }
    public function test() {
        $this->foo();
        static::foo();
    }
}

class B extends A {
   /* foo() will be copied to B, hence its scope will still be A and
    * the call be successful */
}

class C extends A {
    private function foo() {
        /* original method is replaced; the scope of the new one is C */
    }
}

$b = new B();
$b->test();
$c = new C();
$c->test();   //fails
?>

Зауважте:

Пізнє розв'язання статичних прив'язок зупиниться на повністю розв'язаному статичному виклику без жодних запасних варіантів. З іншого боку, статичні виклики з ключовими словами parent:: або self:: пересилатимуть інформацію про виклик.

Приклад #4 Переадресація та непереадресація дзвінків

<?php
class A {
    public static function foo() {
        static::who();
    }

    public static function who() {
        echo __CLASS__."\n";
    }
}

class B extends A {
    public static function test() {
        A::foo();
        parent::foo();
        self::foo();
    }

    public static function who() {
        echo __CLASS__."\n";
    }
}
class C extends B {
    public static function who() {
        echo __CLASS__."\n";
    }
}

C::test();
?>