2013-06-10 15 views
5

Mam problemy z dziedziczeniem PHP. Oto sprawa:Singlety PHP i dziedziczenie

mam tę klasę bazową, 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() { 

    } 
} 

Mam pęczek klas dziedziczących tej klasy Singleton, nazywają je A, B, C, D. Jeden z nich wygląda tak:

namespace My_Namespace; 

class A extends Singleton { 

    protected function __construct() { 

     B::get(); 

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

Teraz, po prostu zrobić A::get() dostać to wszystko w ruch. Konstruktor klasy A jest wywoływany zgodnie z oczekiwaniami. Następnie konstruktor B nazywa się, znowu bez problemu. Teraz robi się dziwnie. Po wywołaniu C::get() rozpoznaje on static::$instance jako już obiekt klasy B i nie tworzy w ogóle C. Wiem, że jeśli je połączę łańcuchowo, to __construct z B-wywołania C::get lub D::get działa, ale to nie jest optymalne dla moich celów. Czy to dlatego, że są w tym samym zakresie? Jeśli tak, czy jest jakiś sposób obejścia tego? Pytam o to raczej ciekawość, a nie cel praktyczny - wiem, że równie dobrze mogę zaimplementować wzór singletonowy w każdym z nich. Jakieś pomysły? Dzięki!

P.S. Proszę, nie ma komentarzy "singletons are evil and you burn in hell". Znam to doskonale.

+1

+1 dla "nie ... palić w komentarzach piekła" – phpisuber01

+1

Wierzę, że odziedziczone klasy wymagają statycznej właściwości, aby instancja została wepchnięta do ... więc dodaj 'protected static $ instance = null; 'do podklas . – Orangepill

+0

@Orangepill masz to. Dodałem tę linię i wszystko działa zgodnie z oczekiwaniami. 'BUT:' W ten sposób cała klasa Singleton i dziedziczenie są bezużyteczne, chociaż ... Chodziło o to, aby w tej klasie była zawarta pojedyncza funkcjonalność. Czy to w ogóle możliwe? –

Odpowiedz

2

Należy pamiętać, że static::$instance = new static dzwoni do konstruktora (w twoim przypadku) A.

Dzięki rozwiązaniu będziesz potrzebować statycznej właściwości dla swojej instancji w swoich podklasach.

Wystarczy dodać

protected static $instance = null; 

do nich, i to powinno działać dobrze.

+0

Dlaczego to działa przez pierwsze dwa razy? Jak to się dzieje, że nie jestem w tym samym zakresie, jak w 'A :: get()' i 'B :: get()' tworzy odpowiednie instancje ale jak tylko trafi 'C :: get()', to powraca do tego, którego użył dla 'B :: get'? Czy to ma jakiś sens? –

+1

To nie działa przez pierwsze dwa razy, to działa po raz pierwszy wywołujemy 'A :: get()'. Następnie wywoływany jest konstruktor 'A', który wywołuje' B :: get() ', niż' $ instance' z ** klasy bazowej * * jest ustawiony (pierwszy raz, kiedy jest ustawiony), a teraz chcesz wywołać 'C :: get()', który sprawdza 'null == static :: $ instance', ale teraz' $ instance' ** (z klasy A) ** jest już obiektem. – bpoiss

+0

Zajęło mi trochę czasu, aby zrozumieć, jak łatwe jest wyjaśnienie. W tym 'static :: $ instance = new static', wywoływany jest konstruktor, który wywołuje inny konstruktor, wszystko przed przypisaniem czegokolwiek do faktycznej zmiennej instancji $, ponieważ nie została jeszcze zwrócona. Głupi ja. Dziękuję za odpowiedź. –

1

Gdy mamy do czynienia z właściwości statycznych, jeśli chcesz właściwości statycznych dziedziczonej klas do różnią się od klas bazowych trzeba dostarczyć do domu na to, aby żyć.

Aby rozwiązać ten problem wystarczy zdefiniować

protected static $instance = null; 

na swojej klasie pochodnej. Jeśli nie, użyje właściwości klasy podstawowej.