Особенности использования static в php

В документации к «Позднему статическому связыванию» есть замечание:

В нестатическом контексте вызванным классом будет тот, к которому относится экземпляр объекта. Поскольку $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();
	}