Что такое поздние статические привязки в PHP?

Что такое поздние статические привязки в PHP?

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

    Позднее статическое связывание пытается решить это ограничение, введя ключевое слово, которое ссылается на класс, который изначально вызывался во время выполнения. Было решено не вводить новое ключевое слово, а использовать static которая уже была зарезервирована.

    Давайте посмотрим пример:

     <?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 работают, сохраняя класс, названный в последнем «непереадресованном вызове». В случае вызовов статических методов это явно названный класс (обычно тот, который находится слева от оператора ::); в случае нестатических вызовов методов это класс объекта.

    «Переадресационный вызов» является статическим, который вводится self:: , parent:: , static:: или, если он идет вверх по иерархии классов, forward_static_call() .

    Функция get_called_class() может использоваться для извлечения строки с именем вызываемого класса, а static:: вводит ее область видимости.

    В руководстве PHP вам обязательно нужно прочитать Late Static Bindings . Однако я постараюсь дать вам краткое резюме.

    В основном, это сводится к тому, что ключевое слово self не соответствует правилам наследования. self всегда разрешает класс, в котором он используется. Это означает, что если вы создадите метод в родительском классе и вызовите его из дочернего класса, то self не буду ссылаться на ребенка, как вы могли бы ожидать.

    Позднее статическое связывание вводит новое использование для ключевого слова static , которое учитывает этот конкретный недостаток. Когда вы используете static , он представляет класс, в котором вы его сначала используете, т.е. он «привязывается» к классу среды выполнения.

    Это две основные концепции. Способ, как self , parent и static работает, когда static находится в игре, может быть тонкой, поэтому вместо того, чтобы подробно останавливаться, я настоятельно рекомендую изучить примеры страниц руководства. Когда вы понимаете основы каждого ключевого слова, примеры совершенно необходимы, чтобы увидеть, какие результаты вы собираетесь получить.

    Существует не очень очевидное поведение:

    Следующий код создает «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 

    Однако, если мы удалим объявление функции classname из бета-класса, в качестве результата получим «alphaalpha».

    Я цитирую из книги: «PHP Master пишет передовой код».

    Поздней статической привязкой была функция, введенная с php 5.3. Это позволяет нам наследовать статические методы из родительского класса и ссылаться на вызываемый дочерний класс.

    Это означает, что вы можете иметь абстрактный класс со статическими методами и ссылаться на конкретные реализации дочернего класса, используя нотацию static :: method () вместо self :: method ().

    Не стесняйтесь также взглянуть на официальную документацию php: http://php.net/manual/en/language.oop5.late-static-bindings.php

    Пример:

     <?php class Animal { public static function StaticCall() { // Parent object invokes its own getAnimalName() // Child object invokes its own getAnimalName() instead of parent's getAnimalName() return static::getAnimalName(); } public static function SelfCall() { return self::getWeight(); } private static function getAnimalName(){ return 'Animal <br />'; } private static function getWeight(){ return '10 kg <br />'; } } class Bird extends Animal { public static function getAnimalName(){ return 'Bird <br />'; } private static function getWeight(){ return '2 kg <br />'; } } echo Animal::StaticCall(); // Animal echo Animal::SelfCall(); // 10 kg echo Bird::StaticCall(); // Bird invokes method from own object echo Bird::SelfCall(); // 10 kg invokes method from parent 

    В приведенном выше коде вы можете увидеть два класса Animal который является родительским классом, и Bird который является дочерним классом. У Animal и Bird есть getAnimalName() и getWeight() . Суперкласс Animal имеет два метода: StaticCall() и SelfCall() .

    Метод StaticCall() вызывает getAnimalName() с помощью static ключевого слова.
    Метод SelfCall() вызывает getWeight() , используя ключевое слово self .

    Теперь у нас есть вопрос: в каком контексте выполняется getAnimalName() ?

    Ответ: static::getAnimalName() идентифицирует контекст и вызывает метод в этом контексте.

    Если вы вызываете Bird::StaticCall() код будет выполнять StaticCall() который находится в Animal . Тогда static::getAnimalName() вызовет и выполнит из Bird метод getAnimalName() .

    Это отличается от self:: , потому что self:: всегда вызывает метод внутри объекта self . В этом случае self::getWeight() определяется в объекте Animal в методе SelfCall() и Bird::SelfCall() будет Затем self::getWeight() вызывает getWeight() в контексте объекта Animal .

    Самый простой пример, чтобы показать разницу.
    Примечание: self :: $ c

     class A { static $c = 7; public static function getVal() { return self::$c; } } class B extends A { static $c = 8; } B::getVal(); // 7 

    Поздняя статическая привязка, обратите внимание на static :: $ c

     class A { static $c = 7; public static function getVal() { return static::$c; } } class B extends A { static $c = 8; } B::getVal(); // 8 

    Например:

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

    Глядя на это из «почему я должен использовать это?» перспектива, это в основном способ изменить контекст, из которого интерпретируется / запускается статический метод.

    С self собой контекст – это тот, где вы определили метод изначально. Со static это тот, с которого вы его вызываете.