В документации к «Позднему статическому связыванию» есть замечание:
В нестатическом контексте вызванным классом будет тот, к которому относится экземпляр объекта. Поскольку
$this->
будет пытаться вызывать закрытые методы из той же области действия, использованиеstatic::
может дать разные результаты. Другое отличие в том, чтоstatic::
может ссылаться только на статические поля класса.
К обращению внимания на это замечание привела неточность, возникшая при реализации нового функционал.
Задача реализовать функцию, которая для всех потомков данного класса возвращает одно и то же значение.
Приведенный нише набросок кода выводит не то что ожидаем увидеть:
<?php /** * Какой-то генератор уникального значения */ class Counter { static public function Get() { static $iCount = 0; return ++$iCount; } } class Prototype { /** * Создает или возвращает "какое-то" значение, относящееся ко всем * потомками данного класса * (одинаковое для всех потомков) */ static private function getM() { static $iMyValue = null; if ( is_null( $iMyValue ) ) { $iMyValue = Counter::Get(); } return $iMyValue; } /** * Получить характеристику, одинаковую для всех представителей * данного класса (фактически instanceOf self ) */ public function P() { return $this->getM(); } } class A extends Prototype { } class B extends Prototype { } echo (new A())->P(), ' ', (new B())->P(); ?>
Результатом выполнения будет:
1 2
В то время как ожидаем результат:
1 1
В данном примере ошибка закралась в фрагменте кода:
public function P() { return $this->getM(); }
В котором статическая функция вызывается в нестатическом контексте.
Такая ситуация может возникнуть в процессе рефакторинга кода, когда не статичная функция ( private function getM() ) преобразуется в статичную, а в остальном коде не меняется ее вызов на self::. В результате получается вызов не общей функции для классов, содержащей статическую переменную, а вызов приватной функции каждого класса.
Чтобы не было такой неточности следует при рефакторинге проверять места вызовов ставшей статической функции, и использовать self:: вместо $this->.
public function P() { return self::getM(); }