Вопрос

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

Это было полезно?

Решение

Вам обязательно нужно прочитать Поздние статические привязки в руководстве PHP.Тем не менее, я постараюсь дать вам краткое изложение.

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

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

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

Другие советы

Начиная с 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:: представляет его сферу применения.

Не очень очевидное поведение:

Следующий код создает «алфавит».

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 пишет передовой код».

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

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

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


Самый ясный способ объяснить позднее статическое связывание — это простой пример.Взгляните на два определения классов ниже и читайте дальше.

class Vehicle {
    public static function invokeDriveByStatic() {
        return static::drive(); // Late Static Binding
    }
    public static function invokeStopBySelf() {
        return self::stop(); // NOT Late Static Binding
    }
    private static function drive(){
        return "I'm driving a vehicle";
    }
    private static function stop(){
        return "I'm stopping a vehicle";
    }
}

class Car extends Vehicle  {
    protected static function drive(){
        return "I'm driving a CAR";
    }
    private static function stop(){
        return "I'm stopping a CAR";
    }
}

Мы видим родительский класс (транспортное средство) и дочерний класс (автомобиль).Родительский класс имеет 2 общедоступных метода:

  • invokeDriveByStatic
  • invokeStopBySelf

Родительский класс также имеет 2 частных метода:

  • drive
  • stop

Дочерний класс переопределяет 2 метода:

  • drive
  • stop

Теперь давайте вызовем публичные методы:

  • invokeDriveByStatic
  • invokeStopBySelf

Спроси себя:Какой класс вызывает invokeDriveByStatic / invokeStopBySelf?Родительский или дочерний класс?

Посмотрите ниже:

// This is NOT Late Static Binding
// Parent class invokes from Parent. In this case Vehicle.
echo Vehicle::invokeDriveByStatic(); // I'm driving a vehicle
echo Vehicle::invokeStopBySelf(); // I'm stopping a vehicle

// This is Late Static Binding.
// Child class invokes an inherited method from Parent.
// Child class = Car, Inherited method = invokeDriveByStatic().
// ...
// The inherited method invokes a method that is overridden by the Child class.
// Overridden method = drive()
echo Car::invokeDriveByStatic(); // I'm driving a CAR

// This is NOT Late Static Binding
// Child class invokes an inherited method from Parent.
// The inherited method invokes a method inside the Vehicle context.
echo Car::invokeStopBySelf(); // I'm stopping a vehicle

А static Ключевое слово используется в шаблоне проектирования Singleton.Смотрите ссылку: https://refactoring.guru/design-patterns/singleton/php/example

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

class A
{
    static $c = 7;

    public static function getVal()
    {
        return self::$c;
    }
}

class B extends A
{
    static $c = 8;
}

B::getVal(); // 7

Позднее статическое связывание, примечание статический::$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, это тот, с которого вы звоните.

Также следите за тем, обновляете ли вы статические переменные в дочерних классах.Я нашел этот (несколько) неожиданный результат, когда дочерний элемент B обновляет дочерний элемент C:

class A{
    protected static $things;
}

class B extends A {
    public static function things(){
        static::$things[1] = 'Thing B';
        return static::$things; 
    }
}

class C extends A{
    public static function things(){
        static::$things[2] = 'Thing C';
        return static::$things;        
    }
}

print_r(C::things());
// Array (
//   [2] => Thing C
// )

B::things();

print_r(C::things()); 
// Array (
//    [2] => Thing C
//    [1] => Thing B
// )

Вы можете это исправить, объявив одну и ту же переменную в каждом дочернем классе, например:

class C extends A{
    protected static $things; // add this and B will not interfere!

    public static function things(){
        static::$things[2] = 'Thing C';
        return static::$things;        
    }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top