2013-06-10 3 views
5

У меня возникли проблемы с наследованием PHP. Вот сделка:PHP-синглтоны и наследование

У меня есть этот базовый класс, Singleton:

namespace My_Namespace; 

abstract class Singleton { 
    protected static $instance = null; 

    static function get() { 
     if (null == static::$instance) { 
      static::$instance = new static; 
     } 
     return static::$instance; 
    } 

    private function __construct() { 

    } 
} 

У меня есть куча классов, наследующих этот класс Singleton, назовем их A, B, C, D. Один из них выглядит следующим образом:

namespace My_Namespace; 

class A extends Singleton { 

    protected function __construct() { 

     B::get(); 

     if (some_condition()) { 
      C::get(); 
     } 
     else { 
      D::get(); 
     } 
    } 
} 

Теперь, я просто сделать A::get(), чтобы получить все это качению. Конструктор A называется, как и ожидалось. Затем строится конструктор B, опять же без проблем. Теперь это странно. Когда вызывается C::get(), он распознает static::$instance как уже объект класса B и не создает экземпляр C вообще. Я знаю, если я вроде как-то их цепочка, то есть __construct из B звонков C::get или D::get это работает, но это не оптимально для моих целей. Это связано с тем, что они находятся в одном и том же объеме? Если да, есть ли способ обойти это? Я задаю это скорее скорее любопытство, чем практическую цель. Я знаю, что я могу так же легко реализовать одноэлементный шаблон в каждом из них. Итак, какие-то идеи? Благодаря!

P.S. Пожалуйста, не «синглтоны злые, а вы должны сжечь в аду». Я это прекрасно знаю.

+1

+1 для 'no ... burn in hell comments' – phpisuber01

+1

Я считаю, что унаследованным классам требуется статическое свойство для того, чтобы экземпляр был заглушен ... поэтому добавьте' protected static $ instance = null; 'в подклассы , – Orangepill

+0

@Orangepill у вас есть. Я добавил эту строку, и все работает так, как ожидалось. 'НО:' Этот тип делает весь класс Singleton и наследование бесполезным, хотя ... Идея заключалась в том, что в этом классе есть одноэлементная функциональность. Возможно ли это вообще? –

ответ

2

Обратите внимание, что static::$instance = new static вызывает конструктор (в вашем случае) A.

С вашим решением вам понадобится статическое свойство для вашего экземпляра в ваших подклассах.

Просто добавьте

protected static $instance = null; 

к ним, и он должен работать нормально.

+0

Почему это работает в течение первых двух раз? Как получилось, если я не в той же области, что и в 'A :: get()' и 'B :: get()', он создает соответствующие экземпляры но как только он попадает в 'C :: get()' он возвращается к тому, который он использовал для 'B :: get'? Это что-то имеет смысл? –

+1

Он не работает в первые два раза, он работает в первый раз Вы вызываете 'A :: get()'. Затем вызывается конструктор 'A', который вызывает' B :: get() ', чем' $ instance' из ** базового класса * * установлен (первый раз, когда он установлен). И теперь вы хотите вызвать 'C :: get()', который проверяет 'null == static :: $ instance', но теперь' $ instance' ** (из класса A) ** уже является объектом. – bpoiss

+0

Подумал, как легко объяснить. В этом 'static :: $ instance = new static' вызывается конструктор, который вызывает другой конструктор, все перед присвоением чего-либо фактической переменной $ instance, потому что она еще не возвращена. Дурак я. Спасибо за ответ. –

1

При работе со статическими свойствами, если вы хотите статические свойства унаследованной методы классов, чтобы отличаться от базовых классов, которые вы должны предоставить дом для того, чтобы жить.

Чтобы решить эту проблему просто определить

protected static $instance = null; 

на ваш производный класс. Если нет, он будет использовать свойство базового класса.