2013-06-10 13 views
5

Ho problemi con l'ereditarietà di PHP. Ecco affare:Singletons PHP ed ereditarietà

ho questa classe di base, 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() { 

    } 
} 

Ho un sacco di classi che ereditano quella classe Singleton, che chiameremo A, B, C, D. Uno di loro si presenta così:

namespace My_Namespace; 

class A extends Singleton { 

    protected function __construct() { 

     B::get(); 

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

Ora, ho solo fare un A::get() per avere tutto a rotazione. Il costruttore di A è chiamato, come previsto. Quindi, il costruttore di B viene chiamato, ancora senza problemi. Ora diventa strano Una volta chiamato C::get(), riconosce static::$instance come già un oggetto di classe B e non crea affatto un'istanza di C. So che se li metto in serie, cioè __construct di B chiama C::get o D::get, ma non è ottimale per i miei scopi. È causato dal fatto che siano nello stesso ambito? Se è così, c'è un modo per aggirare questo? Sto chiedendo questo più alla curiosità che allo scopo pratico - so che posso facilmente implementare il modello singleton in ognuno di essi. Quindi, qualche idea? Grazie!

P.S. Per favore, niente "singleton è male e dovresti bruciare all'inferno". Lo so perfettamente.

+1

+1 per 'no ... burn in hell comments' – phpisuber01

+1

Credo che le classi ereditate abbiano bisogno di una proprietà statica per l'istanza da spingere in ... quindi aggiungi' static static $ instance = null; 'alle sottoclassi . – Orangepill

+0

@Orangepill ce l'hai. Ho aggiunto quella linea e tutto funziona come previsto. 'BUT:' Questo rende l'intera classe Singleton e l'ereditarietà roba inutili però ... L'idea era di avere la funzionalità singleton racchiusa in quella classe. È possibile? –

risposta

2

Nota che static::$instance = new static chiama il costruttore di (nel tuo caso) A.

Con la soluzione, è necessario disporre di una proprietà statica per l'istanza nelle sottoclassi.

Basta aggiungere

protected static $instance = null; 

a loro, e dovrebbe funzionare bene.

+0

Perché funziona per le prime due volte? Come mai se non sono nello stesso scope, come in 'A :: get()' e 'B :: get()' crea le istanze appropriate ma non appena cade 'C :: get()' ricade su quello che usava per 'B :: get'?" Ha senso? –

+1

Non funziona per le prime due volte, funziona per la prima volta si chiama 'A :: get()'. Quindi viene chiamato il costruttore di 'A' che chiama' B :: get() ', rispetto a' $ instance' dalla ** base class * * è impostato (la prima volta che è impostato). E ora si desidera chiamare 'C :: get()', che controlla 'null == static :: $ instance', ma ora' $ istanza' ** (dalla classe A) ** è già un oggetto. – bpoiss

+0

Mi ci è voluto un po 'per capire quanto sia facile la spiegazione. A quel 'static :: $ instance = new static', viene chiamato il costruttore che chiama un altro costruttore, il tutto prima di assegnare qualsiasi cosa alla variabile $ istanza effettiva, in quanto non ha ancora restituito. Silly me. Grazie per la risposta. –

1

Quando si tratta di proprietà statiche se si desidera che le proprietà statico del classi ereditate differiscano dalle classi di base è necessario fornire una casa per poter vivere in.

per risolvere il problema basta definire

protected static $instance = null; 

sulla classe derivata. In caso contrario, utilizzerà la proprietà della classe base.