類與類之間有一種父與子的關系,子類繼承父類的屬性和方法,稱為繼承。在繼承里,子類擁有父類的方法和屬性,同時子類也可以有自己的方法和屬性。
```
<?php
/**
* User: 三千
* Date: 16/3/16
* Time: 下午4:17
*/
class person{
public $name = 'Tom';
public $gender;
static $money = 10000;
public function __construct(){
echo '這里是父類',PHP_EOL;
}
public function say(){
echo $this->name,"\t is ",$this->gender,"\r\n";
}
}
class family extends person{
public $name;
public $gender;
public $age;
static $money = 1000;
public function __construct(){
parent::__construct();
echo '這里是子類',PHP_EOL;
}
public function say(){
parent::say();
echo $this->name,"\t is \t",$this->gender,",and is \t ",$this->age,PHP_EOL;
}
public function cry(){
echo parent::$money,PHP_EOL;
echo '% >_< %',PHP_EOL;
echo self::$money,PHP_EOL;
echo "(*^_^*)";
}
}
$poor = new family();
$poor->name = 'Lee';
$poor->gender = 'female';
$poor->age = 25;
$poor->say();
$poor->cry();
```
返回結果:
```
這里是父類
這里是子類
Lee is female
Lee is female,and is 25
10000
% >_< %
1000
(*^_^*)%
```
在繼承中,用parent指代父類,用self指代自己。
用“::”運算符調用父類方法,“::”操作符還用來作為類常量和靜態方法的調用,不要把這兩種應用混淆。
組合和繼承都是提高代碼可重用性的手段。在設計對象模型時,可以按照語義識別類之間的組合關系和繼承關系。比如,繼承是一種“是、像”的關系,而組合是一種“需要”的關系。利用這條規律,就可以很簡單地判斷出父親與兒子應該是繼承關系,父親與家庭應該是組合關系。還可以從另一個角度看,組合偏重整體與局部的關系,而繼承偏重父與子的關系。
從方法復用角度考慮,如果兩個類具有很多相同的代碼和方法,可以從這兩個類中抽象出一個父類,提供公共方法,然后兩個類作為子類,提供個性方法。這是用繼承語意更好。

組合就沒有這么多限制。組合之間的類可以關系很小,甚至沒有關系

在實際編程中,繼承與組合的取舍往往并不是這么直接明了,很難說出二者是“像”的關系還是“需要”的關系,那么我們就要按照低耦合的標準來決定是繼承還是組合。
耦合是一個軟件結構內不同模塊之間互連程序的度量,也就是不同模塊之間的依賴關系。
低耦合指模塊與模塊之間,盡可能地使模塊間獨立存在;模塊與模塊之間的接口盡量少而簡單。
解耦是要解除模塊與模塊之間的依賴。
如果這樣子還沒有辦法區分兩者,那么傾向于組合。
繼承存在以下問題:
- 1.繼承破壞封裝性。
定義鳥類為父類,具有羽毛屬性和飛翔方法,其子類天鵝、鴨子、鴕鳥等繼承鳥這個類。但是鴕鳥不需要飛翔的方法,但作為子類,他卻可以使用飛翔這個方法,顯然破壞了類的封裝性。
- 2.繼承是緊耦合的。
繼承使得子類和父類捆綁在一起。組合僅通過唯一接口和外部進行通信,耦合度低于繼承。
- 3.繼承擴展復雜
隨著繼承層數的增加和自類的增加,將涉及大量方法重寫,使用組合,可以根據類型約束,實現動態組合,減少代碼。
- 4.不恰當地使用繼承可能違反現實世界中的邏輯
比如,人作為父類
組合也有缺點,在創建組合對象時,組合需要一一創建局部對象,這一定程度上增加了一些代碼,而繼承則不需要這一步,因為子類自動有了父類的方法。
```
<?php
/**
* User: 三千
* Date: 16/3/16
* Time: 下午6:57
*/
class car{
public function addoil(){
echo "Add oil \r\n";
}
}
class bmw extends car{
}
class benz{
public $car;
public function __construct(){
$this->car = new car();
}
public function addoil(){
$this->car->addoil();
}
}
$bmw = new bmw();
$bmw->addoil();
$benz = new benz();
$benz->addoil();
```
上面代碼很顯然,組合比繼承增加了代碼量。不過總體來說,優點大于缺點。
繼承最大的優點就是擴展簡單,但是其缺點大于優點,所以在設計時,需要慎重考慮。
使用繼承的經驗:
- 精心設計專門用于被繼承的類,繼承樹的抽象層應該比較穩定,一般不要多余三層
- 對于不是專門用于被繼承的類,禁止其被繼承,也就是使用final修飾符。使用final修飾符即可防止重要方法被非法覆寫,又能給編輯器尋找優化的機會
- 優先考慮用組合關系提高代碼的可重用性
- 子類是一種特殊的類型,而不只是父類的一個角色
- 子類擴展,而不是覆蓋或者使父類的功能失效
- 底層代碼多用組合,頂層/業務層代碼多用繼承。底層用組合可以提高效率,避免對象臃腫。頂層代碼用繼承可以提高靈活性,讓業務使用更方便。
- 空白目錄
- 第1章 面向對象思想的核心概念
- 1.1 面向對象的“形”與“本”
- 1.1.1 對象的“形”
- 1.1.2 對象的“本質”
- 1.1.3 對象與數組
- 1.1.4 對象與類
- 1.2 魔術方法的應用
- 1.2.1 construct和destruct方法
- 1.2.2 set和get方法
- 1.2.3 call和callStatic方法
- 1.2.4 __toString方法
- 1.3 繼承與多態
- 1.3.1 類的組合與繼承
- 1.3.2 各種語言中的多態
- 1.4 面向接口編程
- 1.4.1 接口的作用
- 1.4.2 對接口的思考
- 1.5 反射
- 1.5.1 如何使用反射API
- 1.6 異常和錯誤處理
- 1.6.1 如何使用異常處理機制
- 1.6.2 怎樣看PHP的異常
- 1.6.3 PHP中的錯誤級別
- 1.6.4 PHP中的錯誤處理機制
- 1.7 本章小結
- 第2章 面向對象的設計原則
- 2.1 面向對象設計的五大原則
- 2.2 一個面向對象留言本的實例
- 2.3 面向對象的思考
- 2.4 本章小結
- 第3章 正則表達式基礎與應用
- 3.1 認識正則表達式
- 3.2 正則表達式中的元字符
- 3.3 正則表達式匹配規則
- 3.4 構造正則表達式
- 3.5 正則在實際開發中的應用
- 3.6 正則表達式的效率與優化
- 3.7 本章小結