2010-10-15 11 views
7

Ho due classi, "A" e "B". Nella logica dell'applicazione nessuno è autorizzato a creare un oggetto di classe "B", ad eccezione della classe "A". Ma, poiché non voglio avere le due classi nello stesso file, non posso limitarlo con la correttezza "privata".Limita ciò che può creare una classe PHP

È possibile creare questo tipo di restrizione? Se qualcun altro allora "A" cerca di creare un oggetto di classe "B", dici di fare pipì !?

+13

mi interessa sapere il motivo per cui si vorrebbe Fai questo? – rojoca

risposta

0

Nel costruttore di B, si richiede che A venga passato. Quando si desidera ottenere B da A, basta creare un B e passare A. Quando viene chiamata la nuova B, sarà necessario passare A.

class A 
{ 
    private $b; 

    private function getB() 
    { 
     if (null === $this->b) 
     { 
      $this->b = new B($this); 
     } 

     return $this->b; 
    } 
} 

class B 
{ 
    public function __construct(A $a) 
    { 

    } 
} 
+1

Ciò potrebbe tecnicamente essere ingannato con '$ a = new A(); $ b = nuovo B ($ a); '... – stevendesu

+0

Pensandoci sul serio, è corretto. Lascia che provi cosa succede se A segue un modello singleton. – MANCHUCK

+0

Si potrebbe anche clonare un'istanza esistente di B. E poiché la classe verrà istanziata da coloro che scrivono il codice in ogni caso, non c'è molto da fare per limitare l'accesso in questo modo. Anche le classi A e B saranno difficili da testare in questo modo, poiché A ha una dipendenza hardcoded e B richiede sempre un A Mock. Fare B a Singleton ti butterà completamente all'inferno. IMO il valore che ottieni per limitare l'accesso non vale la pena. – Gordon

5

si potrebbe ispezionare il backtrace:

class B 
{ 
    public function __construct() 
    { 
     $chain = debug_backtrace(); 
     $caller = $chain[1]['class']; 

     if ('A' != $caller) { 
      throw new Exception('Illegal instantiation'); 
     } 
    } 
} 
+4

Se si va su questa rotta, si dovrebbe profilare il suo rendimento. La funzione è chiamata ** debug ** _backtrace per un motivo. – Gordon

+2

Oh, più d'accordo Gordon, ma è una soluzione! –

7

Questo è il più hacky come ottenere di e non lo deve usare. Ho solo post-it, perché mi piacciono le cose hacky;) Inoltre questo genera un errore se E_STRICT segnalazione degli errori è abilitata:

class B 
{ 
    private function __construct() {} 

    public function getInstance() { 
     if (!isset($this) || !$this instanceof A) { 
      throw new LogicException('Construction of B from a class other than A is not permitted.'); 
     } 

     return new self; 
    } 
} 

class A 
{ 
    function someMethod() { 
     $b = B::getInstance(); // note that I'm calling the non-static method statically! 
    } 
} 

Il motivo per cui questo funziona è una "caratteristica" che può essere visto in the second example of this manual page.

+0

Ricorda che mentre questo funziona, fa sì che PHP sputa un 'E_STRICT'. – BoltClock

+0

Sì, lo dico già nella prima frase;) – NikiC

+0

se qualcuno ** veramente ** vuole usare questo hack, è meglio abilitare 'error_reporting (-1)' e usare '@ $ b = B :: getInstance() ; ', ma non sono sicuro che' @ 'sopprimerà tutti gli avvertimenti/errori generati nel metodo getInstance – Sudhi

0

forse si vuole usare qualcosa di simile:

class A 
{ 
     protected function __construct() 
     { 
     } 
} 

class B extends A 
{ 
     public function __construct() 
     { 
       $a = new A(); 
     } 
} 

$b = new B(); 
-1

Usa get_called_class per scoprire quale classe tenta di creare un'istanza di un oggetto:

class B 
{ 
     public function __construct() 
     { 
       if(get_called_class() != 'A') { 
        //booboo 
       } 
     } 
} 
+0

Ciò funzionerebbe solo se' A' estendesse 'B' e' B' fossero costruiti, non 'A'. – NikiC

Problemi correlati