2012-03-15 76 views
14

在回顧一些PHP代碼時,我發現了一件奇怪的事情。下面是它的簡單的例子說明:PHP繼承,使用子變量的父函數

文件a.php只會:

<?php 
class A{ 
    public function methodA(){ 
     echo $this->B; 
    } 
} 
?> 

文件B.php:

<?php 
    class B extends A{ 
     public $B = "It's working!"; 
    } 
?> 

文件test.php的:

<?php 
    require_once("A.php"); 
    require_once("B.php"); 
    $b = new B(); 
    $b->methodA(); 
?> 

運行test.php輸出「It's working!」,但問題是爲什麼它工作? :)這是一個功能還是錯誤?類A中的方法methodA也可以調用B類中不應該在OOP中工作的方法。

+1

一種方式來測試是創建一個「C」類沒有定義B,看看會發生什麼。儘管如果沒有進行實驗,你所做的將被認爲是瘋狂的設計,但PHP可能足夠聰明以使其能夠在這種情況下工作。 – 2012-03-15 19:51:27

+1

OOP沒有提到調用子類方法是否應該從基類工作。它表示超類方法應該可用於子類(除非被覆蓋),如果有的話......但對於其他方式而言卻相當沉默。實際上,一些最純粹的OOP語言並不在乎。 – cHao 2012-03-15 19:52:13

+0

5 + upvotes?怎麼來的? – 2012-03-15 19:53:08

回答

12

你只是實例化類B。暫時忽略A,並假設methodA()是類B的一部分。

B類延伸A時,它獲得了A的全部功能。在代碼運行之前,不會評估$this->B,而不是之前的評估。因此沒有錯誤發生,並且不會發生,因爲類B中存在$this->B

+3

只能使用公共成員變量。 – hakre 2012-03-15 20:11:44

6

PHP是一種動態語言。方法和數據成員在運行時進行評估。當你調用一個方法或訪問一個成員時,PHP實際上會查找一個排序的散列表來查明這個方法或成員是否可以在這個對象上訪問,或者不可以在繼承層次結構中的任何地方訪問它。

而不僅僅是繼承,你可以隨時在運行時將任意數據分配給一個對象,並且類內的代碼仍然可以使用$ this-> something來訪問它,其中,'something'在類中不存在。

0

B類延伸從A類,因此它繼承類A的方法methodA()

2

作爲PHP是一種動態語言,沒有錯與調用的屬性或方法,其可以在實例中存在正在使用它(在這種情況下是B類的一個實例)

1

PHP是一種動態語言。當在B的實例上調用methodA()時,B的成員$ B確實存在。

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

不起作用。

在某些動態語言中,您甚至可以在運行時定義方法。

1

這對我有意義;由於它出現在類B中,因此$ B在結果對象中可用。由於$ this-> B在運行時計算,並且該值在此之前設置(當類B實例化時),它被發現是正確設置。

你也可以用方法來做到這一點,因爲它們的存在直到它們被執行時才被檢查(雖然通常在方法的情況下在父類中聲明它們是抽象的,因此迫使子實現它們) 。

1

這就是OOP應該如何工作。看起來有點奇怪,因爲你會認爲A必須知道$this->B是什麼(事實上,在某些語言中,這會產生編譯器警告),但是由於您使用的子類,行爲是正確的正在定義你的函數正在尋找的變量。如果你從A()的實例調用methodA(),那麼你會得到一個「未定義」的錯誤。

現在,會是什麼奇怪的(讀:錯誤)是,如果工作:

class A { 
    public $b = "Derp"; 
} 
class B extends A { 
    function sayIt() { echo $this->b; } 
} 
$a = new A(); 
$a->sayIt(); 
3

$this只是一個對象變量 - 一個特殊的一個,因爲它是目前的一個,但它仍然只是一個對象變量。

由於$B::B是一個公共成員變量,因此可以從任何地方訪問可以訪問B實例的引用。與一個對象變量。

隨着公衆成員無處不在,任何功能,即使從A::methodA()內部都可以訪問。

所以沒有太多的實際想知道。您的示例中的類繼承只涉及$this「參數」形式的對象變量的傳遞(不可見),當調用A::methodA()時。

請看下面的例子,可能使得它更加明顯:

function methodA($object) { 
    echo $object->B; 
} 

class B { 
    public $B = "It's working!"; 
    public function methodA() { 
     methodA($this); 
    } 
} 
+0

$這個變量是類B的一個實例。在一個類似的示例變量中,這個在java中也是B的實例。在java例子中,我需要在類A和類B中定義變量B,並且當涉及到打印變量java時打印類A中的一個。 – 2012-03-15 21:24:32

+0

在PHP中,您還需要,例如,如果要使成員受保護,則需要將其定義爲在A中受到保護。由於B從A擴展,A和B定義中的代碼可以訪問它。受保護的成員從外部看不到。私人成員只對當前定義是私有的,所以對於PHP中的私有成員,如果在B中定義了它,則A不能訪問它。 – hakre 2012-03-15 21:44:55