2012-06-17 100 views
3

請通過下面給出的代碼是從PHP手冊延遲靜態PHP 5.3中

<?php 
class A { 
    private function foo() { 
     echo "success!\n"; 
    } 
    public function test() { 
     $this->foo(); 
     static::foo(); 
    } 
} 

class B extends A { 
    /* foo() will be copied to B, hence its scope will still be A and 
    * the call be successful */ 
} 

class C extends A { 
    private function foo() { 
     /* original method is replaced; the scope of the new one is C */ 
    } 
} 

$b = new B(); 
$b->test(); 
$c = new C(); 
$c->test(); //fails 
?> 

任何一個可以解釋究竟是什麼回事約束力?

foo()如何被複制到B?

+0

'foo()'不會被複制,它會被其父'A'繼承。我不明白你的具體問題。當然,它失敗了,因爲你在'C'私有中使你的方法'foo'。將其公開並且會起作用。 –

+0

foo怎麼會被遺傳? ...因爲它是私人的方法...這是從PHP手冊 –

+0

的例子是的,它只是無法訪問。 –

回答

2

foo不會被複制到B本身(它是繼承的,但不可見;請參閱Gordon的下面的評論)。 B繼承A->foo,它調用A->test。爲了演示,看看會發生什麼,當你echo __CLASS__testfoo內(並刪除static::foo()通話,這是造成錯誤):

class A { 
    private function foo() { 
     echo __CLASS__."->foo\n"; 
     echo "success!\n"; 
    } 
    public function test() { 
     echo __CLASS__."->test\n"; 
     $this->foo(); 
    } 
} 

輸出:

A->test 
A->foo 
success! 
A->test 
A->foo 
success! 

這是一因爲它涉及information hiding/encapsulation繼承基礎。這允許你做這樣的事情:

class ListOfThings { 
    // internal structure (top secret!) 
    private $_list = array(); 

    // add item to list 
    public function add($item) { 
     $this->_list[] = $item; 
    } 

    // return number of items in list 
    public function count() { 
     return count($this->_list); 
    } 
} 

class ListOfStates extends ListOfThings { 

    // do we have all 50 states? 
    public function allStatesListed() { 
     return $this->count() === 50; 
    } 

    // try to access internal structure of ListOfThings 
    public function accessInternalStructure() { 
     sort($this->_list); 
    } 
} 

$states = new ListOfStates; 
$states->add('ME'); 
$states->add('NH'); 
$states->add('VT'); 
$states->add('RI'); 
$states->add('CT'); 
var_dump($states->count()); 
var_dump($states->allStatesListed()); 
$states->accessInternalStructure(); 

輸出:

int(5) 
bool(false) 

Warning: sort() expects parameter 1 to be array, null given... 

正如你所看到的,ListOfStates能夠使用的ListOfThings所有的公共功能,即使這些功能都依賴於私有變量$_list。也就是說,ListOfStates不能直接操作$_list;它只能通過ListOfThings中定義的公共功能間接作用於$_list

查看PHP文檔中的Visibility頁面以獲取關於此類事情的更多詳細信息。

+0

foo是私有方法...並且根據可見性私有方法不會繼承到子類 –

+1

@Poonam它*被*繼承。但它不可見,這就是爲什麼你不能訪問它。見http://codepad.viper-7.com/B7OWyr – Gordon

+0

@戈登這不是一個很好的例子,因爲你使用的是變量而不是函數。變量包含肯定需要綁定到實例的數據,因此存在差異。 – Niko

4

我記得現在爲什麼後期靜態綁定是有用的。不幸的是,php.net的例子有點不好解釋。看到這個(修改)例如:

<?php 
class A { 
    private function foo() { 
     echo __CLASS__; 
    } 
    public function test() { 
     $this->foo(); 
     static::foo(); 
    } 
} 

class B extends A { 
    public function foo() 
    { 
     echo __CLASS__; 
    } 
} 

$b = new B(); 
$b->test(); 
?> 

如果你運行上面的代碼,你會發現,它的作品,你會得到AB。爲什麼?

  • 它的工作原理,因爲test()foo()一個公共的getter,因此,如果您從類型A,或者從B類型的對象的對象,從A繼承調用test()也不要緊,因爲test()總會可以訪問定義它的類的私人成員。
  • 第一種情況下,$this->foo();將始終呼叫A::foo(),因爲綁定是在本地完成的,在A的範圍內,這有時是非常不可取的。請參閱此評論:http://www.php.net/manual/en/language.oop5.late-static-bindings.php#83502
  • 在第二種情況下,static::foo();指示口譯員確定$b的類型並查看在哪個類中嘗試查找foo()。在這種情況下,B::foo()被視爲A::foo()的替代方法,因此,基本上,如果B::foo()存在,則會調用它,否則解釋器將查找A::foo()
  • 嘗試將B::foo()標記爲私人並運行我提供的示例,以查看發生了什麼。我認爲這個測試和我上面的咆哮會爲你澄清這個問題;)

此外,我接受任何意見,我上面的觀點,因爲我沒有在很長一段時間使用PHP。

+0

我的問題的劇本:首先它可能會有點奇怪,它會嘗試從'A'的角度訪問B :: foo()(不要忘記'test()'是在' A'),但是,否則它會破壞封裝,所以這就是爲什麼'B :: foo()'需要公開的原因,以便作爲'A :: foo()'的重寫方法。 –

+1

列表中的第二點僅適用於此示例,並非一般。如果A :: foo()被聲明爲public或protected,則輸出爲「BB」。這是因爲私人功能不能被覆蓋。 – Niko

+0

嗯,是的。我希望我的例子不是暗示這種謬論:)順便說一句,感謝編輯。 –