PHP реализует функцию поздних статических привязок, которую можно использовать для ссылки на вызываемый класс в контексте статического наследования.

Точнее, поздние статические привязки работают, сохраняя класс, названный в последнем «вызове без переадресации». В случае вызова статического метода это явно названный класс (обычно тот, что слева от :: оператора); в случае вызовов нестатических методов это класс объекта. «Переадресующий вызов» — это статический вызов, который вводится с помощью self::, parent::, static::или, если он идет вверх по иерархии классов, forward_static_call() . Функцию get_called_class() можно использовать для извлечения строки с именем вызываемого класса и static:: представления его области действия.

Эта функция была названа «поздние статические привязки» с учетом внутренней перспективы. «Позднее связывание» происходит из-за того, что static:: оно не будет разрешено с использованием класса, в котором определен метод, а скорее будет вычислено с использованием информации времени выполнения. Его также называли «статической привязкой», поскольку его можно использовать для (но не ограничиваясь) вызовов статических методов.

Ограничения self::

Статические ссылки на текущий класс типа 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 static::простое использование

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

Приведенный выше пример выведет:

успех!
успех!
успех!


Неустранимая ошибка: вызов закрытого метода C::foo() из контекста 'A' в /tmp/test.php в строке 9

Примечание :

Разрешение поздних статических привязок остановится на полностью разрешенном статическом вызове без отката. С другой стороны, статические вызовы с использованием таких ключевых слов, как 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();
?>