Позднее статическое связывание
Начиная с версии PHP 5.3.0 появилась особенность, называемая позднее статическое связывание, которая может быть использована для того чтобы получить ссылку на вызываемый класс в контексте статического наследования.
Если говорить более точно, позднее статическое связывание сохраняет имя класса указанного в последнем "не перенаправленном вызове". В случае статических вызовов это явно указанный класс (обычно слева от оператора ::); в случае не статических вызовов это класс объекта. "Перенаправленный вызов" - это статический вызов, начинающийся с self::, parent::, static::, или, если двигаться вверх по иерархии классов, forward_static_call(). Функция get_called_class() может быть использована чтобы получить строку с именем вызванного класса, и static:: представляет ее область действия.
Само название "позднее статическое связывание" отражает в себе внутреннюю реализацию этой особенности. "Позднее связывание" отражает тот факт, что обращения через static:: не будут вычисляться по отношению к классу, в котором вызываемый метод определен, а будут вычисляться на основе информации в ходе исполнения. Также эта особенность была названа "статическое связывание" потому, что она может быть использована (но не обязательно) в статических методах.
Ограничения self::
Статические ссылки на текущий класс, наподобие self:: или __CLASS__, вычисляются используя класс, к которому они принадлежат, как к тому, в котором они были определены.
<?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();
/*
A
*/
?>
Использование позднего статического связывания
Позднее статическое связывание пытается устранить это ограничение предоставляя ключевое слово, которое ссылается на класс, вызванный непосредственно в ходе выполнения. Попросту говоря, ключевое слово, которое позволит вам ссылаться на B из test() в предыдущем примере. Было решено не вводить новое ключевое слово, а использовать static, которое уже зарезервировано.
<?php
class A {
public static function who() {
echo __CLASS__;
}
public static function test() {
static::who(); // Здесь действует позднее статическое связывание
}
}
class B extends A {
public static function who() {
echo __CLASS__;
}
}
B::test();
/*
B
*/
?>