2010-10-15 3 views
7

Ich habe zwei Klassen, "A" und "B". In der Anwendungslogik darf niemand ein Objekt der Klasse "B" mit Ausnahme der Klasse "A" erstellen. Aber da ich nicht die zwei Klassen in der gleichen Datei haben möchte, kann ich es nicht mit der "privaten" Eigenschaft einschränken.Einschränken, was eine PHP-Klasse erstellen kann

Ist es möglich, diese Art von Einschränkung zu erstellen? Wenn jemand anderes als "A" versucht, ein Objekt der Klasse "B" zu erstellen, sagst du piss off !?

+13

Ich bin daran interessiert zu wissen, warum Sie wollen würde, mach das? – rojoca

Antwort

0

Im Konstruktor von B, muss A übergeben werden. Wenn Sie dann B von A bekommen wollen, erstellen Sie einfach ein B und übergeben Sie A. Wenn neues B aufgerufen wird, muss A übergeben werden.

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

Dies könnte technisch mit $ a = new A() ausgetrickst werden; $ b = new B ($ a); '... – stevendesu

+0

Eigentlich darüber nachdenken, das ist richtig. Lassen Sie mich testen, was passiert, wenn A einem Singleton-Muster folgt. – MANCHUCK

+0

Sie könnten auch eine vorhandene Instanz von B klonen. Und da die Klasse von denjenigen instanziiert wird, die den Code trotzdem schreiben, ist es sehr wenig sinnvoll, den Zugriff auf diese Weise zu beschränken. Klasse A und B werden ebenfalls eine Belastung sein, um auf diese Weise zu testen, da A eine hardcodierte Abhängigkeit hat und B immer einen A Mock benötigt. Making B ein Singleton wird dich komplett in die Hölle werfen. IMO der Wert, den Sie erhalten, um den Zugang zu beschränken, ist die Strafe nicht wert. – Gordon

5

Sie den Backtrace inspizieren konnte:

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

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

Wenn Sie diese Route gehen, sollten Sie profilieren, wie es funktioniert. Die Funktion heißt aus irgendeinem Grund ** debug ** _backtrace. – Gordon

+2

Oh, mehr als vereinbart Gordon, aber es ist eine Lösung! –

7

Dies ist als hacky, wie es ist und Sie sollten es nicht verwenden. Ich poste es nur, weil ich Hacky Dinge wie;) Des Weiteren wird diese einen Fehler auslösen, wenn E_STRICT Fehlerberichterstattung aktiviert ist:

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! 
    } 
} 

Der Grund, warum dies funktioniert, ist ein „Feature“, das in the second example of this manual page gesehen werden kann.

+0

Bedenken Sie, dass dies zwar dazu führt, dass PHP ein 'E_STRICT' ausspuckt. – BoltClock

+0

Ja, das sage ich schon im ersten Satz;) – NikiC

+0

wenn jemand ** wirklich diesen Hack benutzen will, aktiviert er besser 'error_reporting (-1)' und benutzt '@ $ b = B :: getInstance() ; ', aber ich bin mir nicht sicher, ob '@' alle in der getInstance-Methode generierten Warnungen/Fehler unterdrückt – Sudhi

0

Vielleicht möchten Sie etwas verwenden:

class A 
{ 
     protected function __construct() 
     { 
     } 
} 

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

$b = new B(); 
-1

Verwenden get_called_class, um herauszufinden, welche Klasse versucht, ein Objekt zu instanziieren:

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

Dies würde nur funktionieren, wenn 'A' erweitert würde' B' und 'B' wurden konstruiert, nicht' A'. – NikiC