Одна из трудноуловимых ошибок
В одном из проектов, которые я сопровождаю, обнаружилась одна мерзкая и трудноуловимая ошибка, связанная с использованием статических переменных внутри методов.
Рассмотрим простой пример PHP-кода:
class A {
public function __construct()
{
static $i = 0;
++$i;
print $i . "\n";
}
}
$a = new A();
$b = new A();
?>
Внимание, вопрос: что будет выведено на экран (очень хороший вопрос для собеседования)?
Правильный ответ:
2
Дело всё в том, что хоть экземпляра класса у нас два, но класс как код только один. Поэтому статическая переменная внутри конструктора тоже всего одна. А такие вот ошибки иногда бывает очень трудно отследить, особенно, если код написан для PHP4 и при использовании очень большой иерархии классов.
Код, подобный приведённому выше, отлично работает, когда имеется только один экземпляр класса; при появлении дополнительных экземпляров (особенно, если они создаются по какому-нибудь условию) приводит к трудноуловимым ошибкам.
Если всё же по каким-либо причинам нужно использовать статическую переменную внутри метода (может быть, статическая переменная класса будет лучшим выбором?), нужно использовать шаблон проектирования “Одиночка” (известный как Singleton):
class A {
public static function instance()
{
static $self = false;
if (false === $self) {
$self = new A();
}
return $self;
}
protected function __construct()
{
static $i = 0;
++$i;
print $i . "\n";
}
public function __clone()
{
trigger_error("Все козлы!", E_USER_ERROR);
}
}
$a = A::instance();
$b = A::instance();
?>
Документация PHP предлагает альтернативный метод создания Одиночек.