PHP 進階之 抽象類(abstract)、接口(interface)、Trait(特征)
抽象類
PHP 5 支持抽象類和抽象方法。定義為抽象的類不能被實例化。
- 抽象方法只能在抽象類中,抽象類中可以包含非抽象方法
- 被定義為抽象的方法只是聲明了其調用方式(參數),不能定義其具體的功能實現
- 繼承一個抽象類的時候,子類必須定義父類中的所有抽象方法,另外,這些方法的訪問控制必須和父類中一樣(或者更為寬松)。
抽象方法給我們提供了一個很好的保護父類的方法
class Fruit { private $color; public function eat() { //chew } public function setColor($c) { $this->color = $c; } } class Apple extends Fruit { public function eat() { //chew until core } } class Orange extends Fruit { public function eat() { //peel //chew } }
上面定義了一個`水果父類` ,同時定義了兩個子類`Apple`,`Orange`,此時
$apple = new Apple();$apple->eat(); //實例化Apple類,調用eat方法,這沒毛病 $fruit = new Fruit(); $fruit->eat(); //如果實例化Friut類,調用eat方法就有點奇怪了,What does that taste like???
抽象方法完美的解決了這個問題
abstract class Fruit { private $color; abstract public function eat(); public function setColor($c) {$this->color = $c; } }
因此,如果我們需要一個類的子類都實現同一個方法,每個方法的實現方法都不同,此時可以使用抽象方法
接口
使用接口(interface),可以指定某個類必須實現哪些方法,但不需要定義這些方法的具體內容。
- 接口中只能定義方法名(含參數),不能有方法體
- 接口中定義的所有方法都必須是公有 (public)
- 要實現一個接口,使用 implements 操作符,類中必須實現接口中定義的所有方法
- 設計接口時如果不確定方法參數個數,可以使用 ...$argumens 可變參數代替,或者直接為空,子類中通過傳入可變參數或者通過 func_get_args 獲取
- 一個類可以同時實現多個接口,實現多個接口時,接口中的方法不能有重名
- 接口也可以繼承,通過使用 extends 操作符
- 接口中也可以定義常量
通過接口我們可以很好的降低代碼的耦合性
例如:
我有一個數據庫,我想寫一個類去訪問我的數據庫,所以我定義了一個接口
interface Database { function listOrders():array; //要求次方法返回的數組 function addOrder(array $arr); //要求次方法參數類型為數組 function removeOrder(); ... }
現在我們使用MYSQL數據庫,所以我寫了一個mysql的類
class MySqlDatabase implements Database { function listOrders() :array{... }
過了一段時間,我們又想改成Oracle數據庫,我們又寫了一個oracle數據庫類去實現接口
class OracleDatabase implements Database { public function listOrders() :array{... }
因為我們使用了接口,所有的方法(參數、返回值)都一致,我們只需要修改一行代碼即可完成切換
$database = new OracleDatabase();
Trait
從PHP的5.4.0版本開始,PHP提供了一種全新的代碼復用的概念,那就是Trait。Trait其字面意思是”特性”、”特點”,我們可以理解為,使用Trait關鍵字,可以為PHP中的類添加新的特性。
熟悉面向對象的都知道,軟件開發中常用的代碼復用有繼承和多態兩種方式。在PHP中,只能實現單繼承。而Trait則避免了這點。下面通過簡單的額例子來進行對比說明。
trait ezcReflectionReturnInfo { function getReturnType() { /*1*/ } function getReturnDescription() { /*2*/ } } class ezcReflectionMethod extends ReflectionMethod { use ezcReflectionReturnInfo; /* ... */ } class ezcReflectionFunction extends ReflectionFunction { use ezcReflectionReturnInfo; /* ... */ }
聲明一個trait 直接使用 trait 關鍵字 + 類名即可 , 與聲明一個類相似
使用trait 使用關鍵字 use + 類名
註意:從基類繼承的成員會被 trait 插入的成員所覆蓋。優先順序是來自當前類的成員覆蓋了 trait 的方法,而 trait 則覆蓋了被繼承的方法。
PHP 進階之 抽象類(abstract)、接口(interface)、Trait(特征)