#7.15 php ООП Позднее статическое связывание. Отличия self:: и static::. Использование static:: в нестатическом контексте

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

<?php
class Animal
{
    const NAME = 'Animal';

    public static function who()
    {
        echo "this is ", self::NAME;
    }
}

class Lion extends Animal
{
    const NAME = 'Lion';
}

Lion::who();

получим строку

this is Animal.

Для того, чтобы получить доступ к константе NAME класса-наследника, вместо self мы должны использовать ключевое слово static:

<?php
class Animal
{
    const NAME = 'Animal';

    public static function who()
    {
        echo "this is ", static::NAME;
    }
}

class Lion extends Animal
{
    const NAME = 'Lion';
}

Lion::who();

Теперь результатом будет строка

this is Lion.

Таким образом, использование static:: позволяет переопределять статические свойства, методы и константы в производных классах.

Внутреннее отличие использования self:: и static:: состоит в том, что имя класса, на который ссылается static, определяется при исполнении соответствующей строки кода, тогда как значение self::NAME вычисляется уже на этапе компиляции программы. Поэтому реализуемая с помощью конструкции static:: функциональность называется поздним статическим связыванием.

Использование static:: в нестатическом контексте

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

<?php
class Animal
{
    const NAME = 'Animal';

    public function who()
    {
        echo "this is ", static::NAME;
    }
}

class Lion extends Animal
{
    const NAME = 'Lion';
}

$lion = new Lion;
$lion->who();

Результатом будет:

this is Lion.

В нестатическом контексте $this-> и static:: часто могут быть взаимозаменяемы. Однако, в отличие от $this->, конструкция static:: не позволяет ссылаться на нестатические переменные (ссылаться на нестатические методы с её помощью можно).

Существует ещё одно отличие. $this-> и static:: дадут разные результаты при обращении из метода базового класса к недоступному (private) переопределенному методу класса-наследника. Рассмотрим пример.

<?php
class Animal
{
    private function print_title()
    {
        echo "this is Animal<BR>";
    }
}

class Lion extends Animal
{
}

class Wolf extends Animal
{
    private function print_title()
    {
        echo "this is Wolf<BR>";
    }
}

Класс Animal имеет двух наследников Lion и Wolf, один из которых переопределяет private-метод print_title базового класса.

Добавим в базовый класс Animal метод test для демонстрации различий использования конструкций $this-> и static:: при обращении к переопределенному private-методу, и создадим объекты классов-наследников:

<?php
class Animal
{
    private function print_title()
    {
        echo "this is Animal<BR>";
    }

    public test()
    {
        $this->print_title();
        static::print_title();
    }
}

class Lion extends Animal
{
}

class Wolf extends Animal
{
    private function print_title()
    {
        echo "this is Wolf<BR>";
    }
}

$lion = new Lion;
$wolf = new Wolf;

Поскольку класс Lion не переопределяет метод print_title базового класса, то в результате вызова

$lion->test();

будут выполнены строки $this->print_title() и static::print_title(), которые дадут одинаковые результаты. А именно, в обоих случаях будет вызван метод print_title базового класса, и на экран будут выведены строки:

this is Animal
this is Animal

При вызове

$wulf->test();

в результате выполнения строки $this->print_title() PHP осуществит вызов соответствующего перекрытого метода "родного" класса (т.к. метод print_title класса Wolf недоступен), результатом которого снова будет строка

this is Animal

Наконец, строка static::print_title() приведет к ошибке времени исполнения:

Fatal error: Uncaught Error: Call to private method Wolf::print_title() from scope Animal,

поскольку в данном случае static явно ссылается на имя класса Wolf, метод которого print_title не доступен из базового класса.

vedro-compota's picture

хорошая тема, тут же должны быть раскрыта разница между self:: и static::

_____________
матфак вгу и остальная классика =)