2012-02-13 121 views
1

我有一個班,其中$name設置爲'bob'。在兒童班,我把$name設置爲'Karen',但它不起作用。爲什麼你不能在子類中用常量覆蓋父變量? (PHP)

在我的回聲陳述中,第一個表示「bob」而不是「Karen」。第二個,使用子類方法,雖然工作。

這是爲什麼?

class First { 

    public $name; 

    public function __construct() { 

     $this->name = 'bob'; 
    } 
} 

class Third extends First { 

    public $name = 'Karen'; 
    public function set_name ($name) { 
     $this->name = $name; 
    } 
} 

$instance_of_third = new Third; 
$third_name = $instance_of_third->name; 

echo "<br />We're looking for Karen: $third_name<br />"; 
// $third_name here is 'bob' from parent class 

$instance_of_third->set_name("Karen"); 
$third_name = $instance_of_third->name; 
// $third_name here is 'Karen' only after using set_name() 
echo "<br />We're looking for Karen: $third_name<br />"; 

編輯:我添加了2行顯示輸出是什麼。

即使$name在子類中明確設置爲'Karen',它將顯示爲'bob',除非使用set_name()函數來更改它。

回答

4

因爲您的Third沒有自己的構造函數,所以它將繼承First的構造函數。繼承在超類型和子類型之間創建行爲 - 關係。

因此,當您創建Third的新實例時,實例將具有'Karen'的$name屬性,但隨後將調用繼承的構造函數。這就給了Bob的名字。如果您不希望在子類型中出現該行爲,則必須向Third添加一個空的構造函數,例如,

class Third extends First 
{ 
    public function __construct() 
    { 
     // prevents parent First::__construct 
    } 
} 

demo

另一種方法是,以除去構造函數(或至少不設置在它$name)和在父給Bob預設$name屬性。然後你的最初想法可以起作用,例如

class First 
{ 
    public $name = 'Bob'; 
} 

class Third extends First 
{ 
    public $name = 'Karen'; 
} 

demo

請檢查繼承和知名度章節PHP手冊:

+0

奇怪的是我期望如果有人想擴展一個類並改變其中一個屬性,他們可以像我一樣明確地完成它,而不必編寫一堆構造函數代碼。 – 2012-02-13 08:42:38

+1

@ButtleButkus看到我的更新。你可以做到這一點。你只需要明白初始化一個新實例的順序是:'new Foo' - >用默認屬性創建'Foo'的新實例 - >然後在該實例上自動調用'__construct'來做額外的初始化。 – Gordon 2012-02-13 08:53:11

1

當你創建一個類的對象,然後調用構造函數。

因此,父類的構造函數將在您的情況下寫入$ name的值。

+0

$ name在子類中設置。你的答案似乎是說,首先調用構造函數,但那不是發生了什麼。它看起來像$名首先被設置然後被構造函數覆蓋...? – 2012-02-13 08:36:57

+0

不,變量先初始化,然後構造函數調用 – Gaurav 2012-02-13 08:38:23

+0

嗯,這很奇怪。謝謝。 – 2012-02-13 08:40:25

1

因爲構造函數在字段被初始化後被調用,所以它覆蓋了你的$ name字段。

+0

這似乎是發生了什麼,但這不是很奇怪嗎?如果你明確地設置了孩子班的價值,你不認爲這是你會得到的價值嗎?或者您是否使用子類構造函數來更改它? – 2012-02-13 08:40:03

+0

如果不在方法中更改它,比如構造函數,您將獲得該值。簡單地說,你的代碼確實:1)創建一個name ='Karen'的對象; 2)'new'調用構造函數並將其更改爲'Bob'; 3)對象被分配給一個變量。 – meze 2012-02-13 08:43:56

0

翻譯很可能是從上到下閱讀,就像我們一樣。

在第一個示例中,您將公共變量設置爲Karen,但由於子類繼承了第一個類的構造函數,因此將設置「Bob」。

+0

嗯,從上到下閱讀我會認爲你會用它的繼承值'bob'實例化子類,然後在子類中找到'Karen'並覆蓋'bob'。 – 2012-02-13 08:38:40

+0

是的,但是當類被實例化時,構造函數被調用,並將其設置爲Bob。 :) – Jeff 2012-02-13 08:51:41

1

該構造函數重寫默認值。 (通常是因爲它的默認值實例化之後調用),更健壯的方式將類似於這樣:

class First { 
    public $name; 
    public function __construct($name) { 
     $this->name = $name; 
    } 
} 

由然後調用它:

$first_instance = new First("Bob"); 

它也將延伸到Third類。

0

嘗試聲明$名稱爲靜態。例如通過Third :: $ name訪問它。

class First { 

    public static $name; 

    public function __construct() { 

     self::$name = 'bob'; 
    } 

    // edit late static binding 
    public function getName() { 
     return static::$name; 
    } 


} 

class Third extends First { 

    public static $name = 'karen'; 

} 

$instance_of_third = new Third(); 
//$third_name = $instance_of_third::$name; 
$third_name = $instance_of_third->getName();  

echo "<br />We're looking for Karen: $third_name<br />"; 
+0

,它不能解決OP的問題。或者說,確實如此,但它不再以核心問題爲重點。 OP難以理解PHP如何繼承。 – Gordon 2012-02-13 08:58:01

+0

因此,靜態變量可以通過簡單的賦值來覆蓋。您的代碼有效,但奇怪的是Dreamweaver在「$ third_name = $ instance_of_third :: $ name;」中突出顯示錯誤 – 2012-02-13 09:10:45

+0

我編輯過這個例子。你也可以在父類中聲明一個名爲getName()的函數。 getName返回與該類關聯的名稱。這在php 5.3中起作用,被稱爲晚期靜態綁定。舉個例子:$ first = new First(); $ first-> getName()會返回Bob等。 – busypeoples 2012-02-13 09:19:07