## Позднее статическое связывание

Позднее статическое связывание в 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();

    ?>

Результат выполнения приведённого примера:

    A

### Пример позднего статического связывания

Позднее статическое связывание стремится устранить это ограничение и вводит ключевое слово для ссылки на класс, который изначально вызвали в ходе исполнения программы. По сути, это ключевое слово, которое в предыдущем примере разрешило бы ссылаться на класс `B` из метода `test()`. Вместо введения нового ключевого слова для позднего статического связывания разработчики языка выбрали ключевое слово `static`, которое зарезервировали прежде.

Пример #2 Пример позднего статического связывания через конструкцию `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

> Замечание:

> В нестатическом контексте классом вызова будет класс экземпляра объекта. Обращение через конструкцию `$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() скопируется в класс В из класса A, поэтому областью действия метода
          по-прежнему будет класс А, и вызов будет успешным */
    }

    class C extends A
    {
        private function foo()
        {
            /* Этот метод заменил собой исходный; область действия нового метода — класс С */
        }
    }

    $b = new B();
    $b->test();

    $c = new C();
    try {
        $c->test();
    } catch (Error $e) {
        echo $e->getMessage();
    }

    ?>

Результат выполнения приведённого примера:

    Success!
    Success!
    Success!
    Call to private method C::foo() from scope A

> Замечание:

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

>     ?>

> Результат выполнения приведённого примера:

>     A
>     C
>     C

`↑` and `↓` to navigate • `Enter` to select • `Esc` to close • `/` to open