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


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

7 116

7 ответов:

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

поздняя статическая привязка пытается решить это ограничение, введя ключевое слово, которое ссылается на класс, который был первоначально вызван во время выполнения. Было решено не вводить новое ключевое слово, а использовать 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. Тем не менее, я постараюсь дать вам краткое резюме.

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

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

это две основные концепции, стоящие за ним. Кстати self,parent и , когда 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 () нотации вместо самость:: метод ().

не стесняйтесь взглянуть на официальную документацию 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() определяется в object Animal методом SelfCall() и Bird::SelfCall() будет называться тогда self::getWeight() вызывает getWeight() в контексте

самый простой пример, чтобы показать разницу.
Заметьте, 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, это тот, от которого вы его вызываете.