2012-09-13 41 views
3

我有兩個類AB,都從同一父母繼承。在PHP中,有沒有辦法確保類B不能在類A內實例化?有沒有辦法阻止一個類不是從一個特定的其他類的實例中被安裝?

B類不是A一個孩子。)

+0

您是否希望B僅在**類'A'內部實例化[即從'A'的方法]還是'A'的實例? – moonwave99

+0

@ moonwave99 - 只在'A'內。我在編輯標題,這是不明確的。 – JDelage

+0

查看我的關於編譯'buildB()'方法的私人編輯,你完成了^^ – moonwave99

回答

1

我不是從PHP的角度思考這一點,但更多的從空中接力身邊...想你可以做到的唯一事情是這樣的,如果您將B的構造函數設爲private,然後公開一個接受A參數和B out參數的靜態方法,然後該方法可以私有實例化B並通過out參數將其返回給A.

//Pseudocode, language-indifferent 

    class A{ 
     var _B; 

     public B GetMeAnInstanceOfB(){ 
      _B=B.CreateInstanceOfB(this); 
     } 

     //alternate 
     public B GetMeAnotherInstanceOfB(){ 
      _B=new B(this); 
     } 
    } 

    class B{ 
     private B(); 
     //alternate 
     private B(A); 
     static B CreateInstanceOfB(A){ 
      return new(b); 
     } 
    } 

這是非常粗糙,可能充滿坑窪,但有刺。從技術上講,A的子類仍然可以得到B,所以如果你封閉了類(阻止了子類),那將會關閉該門。

有趣的問題,是的......

編輯:這個MOD真的沒有解決問題,但也許是更好 - 我創造了B中的公共構造函數(?)一個A作爲參數,和B的實例,現在僅發生A.唯一的問題是,它與同樣的問題JDelage指出,仍然存在 - 如果我實例化一個,我可以建立A B ...

+0

是的,我正在研究PHP,但問題實際上是語言不可知的。這是一個很酷的想法,你在這裏。我喜歡。 – JDelage

+0

如果語言不可知,則在'A'中定義嵌套的私有類'B'。不幸的是,這[用PHP無法完成](http://stackoverflow.com/questions/1548286/can-you-have-nested-classes-in-php)。然而,在SO上發佈了一些解決方法。 – Josh

+0

@Josh非常有效的觀點,但是OP確實說明B不是A的孩子,所以我對這個定義採取了一點自由,以免嵌套。我知道嵌套不會讓他們成爲面向對象的層級意義上的孩子,但是將它們分開在OP提供的上下文中是有效的。 –

1

是。

您如何去實現它,使課堂B的構造函數接受一個參數。並定義一個方法A,使B的對象。

死亡或擲execption如果$argument == null || !($argument instanceof A)

示例代碼:

class X { 
    public $i = 0; 
    public function getI() { 
     return $i; 
    } 
    public function setI($x) { 
     $i = $x; 
    } 
} 

class A extends X { 
    public function setI($x) { 
     $i = $x * 2; 
    } 
    public function makeB($var){ 
     $b = new B($var); 
    } 
} 

class B extends X { 
    public function __construct($a) { 
     if (null == $a) { 
      echo "no arguments given!\r\n"; 
      //exit; 
     }else if (!($a instanceof A)) { 
      echo "disallowed\r\n"; 
      //exit; 
     }else{ 
      echo "initialized b\r\n"; 
     } 
    } 
    public function setI($x) { 
     $i = $x * 3; 
    } 
} 

$a = new A(); 

$a->makeB(); 
$a->makeB(new X()); 
$a->makeB(&$a); 

輸出:

Warning: Missing argument 1 for A::makeB(), called in file.php 
no arguments given! 
disallowed 
initialized b 

你可以看到一個演示here

+0

這與@David類似W的答案除了'$ i'外。我不明白'$我''做什麼。 – JDelage

+0

啊,這只是我添加的一個虛擬屬性。你可以忽略它。 – Prasanth

+0

好的,我認爲可能是這樣,它只是把我扔了。 – JDelage

4

使用debug_backtrace

class Ancestor{} 

class A extends Ancestor{ 

    public function buildB() 
    { 

     return new B; 

    } 

} 

class B extends Ancestor{ 

    public function __construct(){ 

     $backtrace = debug_backtrace(); 
     if($backtrace[1]['class'] !== 'A') 
      throw new Exception("Don't you dare!"); 

     echo "Built successful!\n"; 

    } 

} 

試試:

//Everything ok this way: 
$a = new A; 
$a -> buildB(); 

// You will have an exception in any other case: 
try{ 

    $b = new B; 

}catch(Exception $e){ 

    echo $e -> getMessage(); 

} 

編輯:如果你想確保創建B只是內部A的代碼,你可以做的一樣好 - 只是使buildB私人^^。

+1

哦,很好。我不會想到這一點。 – JDelage

+0

我會做一些測試,看看debug_backtrace()是否足夠好,這是一個可行的解決方案。否則,如果沒有這個要求,你可能會更好。從一般的觀點來看,解耦的代碼比緊密耦合的代碼更好,並且強制執行這個要求違背了這個基本原則。話雖如此,你的具體情況可能需要這個要求,但如果我設計這個,我會考慮一個不同的類結構。 –

+0

@ moonwave99,雖然這是一個聰明的做法 - +1 –

相關問題