2012-10-05 136 views
12

我發現PHP中似乎是一個奇怪的繼承問題。PHP繼承和受保護的成員可見性

​​:

議員申報保護只能在類 本身和繼承和父類訪問。

對我來說,這意味着:如果A instanceof BB instanceof A A可以訪問B的受保護成員。然而,如果A和B都擴展Foo,並且Foo有一個在B中沒有被覆蓋的受保護的構造函數,那麼我可以從A中創建一個B實例。這對我來說沒有意義,因爲A是不是B和B的實例不是A的實例。我也可以從A中調用受保護的方法$b->test(),該方法執行B中實現的方法。(如果B不重新聲明test(),則執行Foo中的實現。)對我來說,這更奇怪,因爲如果B直接實現受保護的構造函數,我不能從A中創建B的實例。看起來很奇怪,我無法訪問受保護的構造函數(也在父類中聲明),但訪問受保護的方法(也在父類中聲明)是沒有問題的。

請注意,當我使用不擴展Foo的類C時,我確實會得到預期的行爲。如果我嘗試從C中實例化B,那麼我得到一個致命錯誤,因爲我試圖訪問受保護的構造函數。如果我向B添加公共構造函數,可以實例化它(這是預期的),我仍然無法訪問受保護的方法test()(這也是預期的行爲)。我期待相同的行爲使用A,而不是C.

示例代碼,再次說明了當:

class Foo { 
    protected function __construct() { 
     echo('Constructing ' . get_called_class()); 
    } 

    protected function test() { 
     echo('Hello world ' . __METHOD__); 
    } 
} 

class A extends Foo { 
    public function __construct() { 
     parent::__construct(); 
    } 

    public function testB() { 
     // Both of these lines work 
     $b = new B(); 
     $b->test(); 
    } 
} 

class B extends Foo { 
    protected function test() { 
     echo('Hello world Again ' . __METHOD__); 
    } 
} 

class C { 
    public function __construct() { 
    } 

    public function testB() { 
     // Both of these lines cause fatal errors 
     $b = new B(); 
     $b->test(); 
    } 
} 

$a = new A(); 
$a->testB(); 

$c = new C(); 
$c->testB(); 

我可能沒有看到的東西,但我找不到什麼。任何人都可以向我解釋行爲嗎?

+0

很奇怪的行爲確實如此。 – Sherlock

+0

你想解釋這個行爲背後的原理或實現嗎?由於這是PHP,所以*很可能沒有理由。 – Jon

+0

如果有理由,我想知道它是什麼。 – Arjan

回答

6

您可以訪問這些方法,因爲在Foo中有一個聲明,它們是您的父母並且允許您訪問它。如果您從父項中移除聲明並在B中聲明受保護的方法,則會發生致命錯誤。

此報告爲PHP https://bugs.php.net/bug.php?id=50892

+0

如果'B'覆蓋'__construct',即使'Foo'聲明它,你也不能從'A'調用'new B()'。 –

+2

感謝您將我指向bugs.php.net鏈接。我在那裏搜索,但無法找到錯誤報告。 – Arjan

1

的錯誤有沒有這個理由,已經2年前報道:https://bugs.php.net/bug.php?id=52120

+0

感謝您的鏈接。我認爲更奇怪的是,你可以調用繼承的保護方法,而不是調用繼承的構造函數(這是預期的行爲,imo) – Arjan