基於介面的程式設計
作為一個PHP程式設計師,學習如何基於介面進行程式設計改變了我的人生,大大提升了我透過整合第三方PHP元件來完善我的專案的能力。介面並不是新的功能,但是它卻是你日常工作中必須了解和使用的重要特性。
那麼PHP的介面到底是什麼?介面是兩個PHP物件之間的契約,一個物件呼叫另一個物件時並不需要知道對方是什麼,而只需要知道對方能做什麼。介面可以降低我們程式碼依賴關係的耦合性,允許我們的程式碼呼叫任何實現了期望介面的第三方程式碼。我們只需要關心第三方的程式碼是否實作了介面就行,而根本不用關心第三方程式碼是如何實作這些介面的。我們來看一個現實中的例子。
假設我到佛羅裡達的邁阿密參加Sunshine PHP開發者大會。我想去城裡逛逛,所以我直接去了當地的汽車租賃公司。他們有一輛現代緊湊型的小車,一輛斯巴魯的旅行車和一輛布加迪威龍(太讓我驚訝了)。我知道我只是想藉助某個交通工具去城裡逛逛,這三輛車都可以滿足我的需求。但是每輛車又是那麼的與眾不同。現代雅紳特還不錯啦,但是我喜歡更有活力一點的。我沒有孩子,所以旅行車還是大了點。那麼,好吧就選布加迪好了。
現實是,我駕駛這三輛車中的任意一輛都可以,因為它們都共享了公用的、已知的介面。每輛車都有一個方向盤、一個油門踏板、一個煞車踏板和方向燈,每輛車都使用汽油作為燃料。但是布加迪的動力強大到我都無法駕馭,但是現代車的駕駛接口卻和它一模一樣。因為三輛車都共享了同樣的已知的接口,但我有機會可以選擇我更喜歡的車型(實話實話,最終我可能還是會選擇現代)。
在PHP的物件導向方面也有同樣的概念。如果我的程式碼中使用了某個特定的類別(代表了特定的實作)的對象,那麼我的程式碼的功能也固然變得非常有限,因為它只能永遠使用那個類別的對象。然而,如果我的程式碼將要用到的是一個接口,我的程式碼立刻就能知道如何去使用任何實現了這個接口的對象。我的程式碼根本不用關心接口是如何實現的,我的程式碼只關心對像是否實現了接口,讓我們用一個例子把這一切解釋清楚。
假設我們有一個PHP類名叫DocumentStore可以從不同的數據源中獲取數據,它可以從一個遠程的地址中獲取HTML,也可以從文檔流中讀取數據,還可以獲取終端的命令行輸出。每個保存在DocumentStore實例中的文件都有一個唯一的ID。範例 2-6 展示了DocumentStore類別。
範例 2-6 DocumentStore類別的定義
class DocumentStore { protected $data = []; public function addDocument(Documentable $document) { $key = $document->getId(); $value = $document->getContent(); $this->data[$key] = $value; } public function getDocuments() { return $this->data; } }
例子2-7 Documentable接口的定義
interface Documentable { public function getId(); public function getContent(); }
那麼這樣做的好處是什麼?好處是我們可以分別建構多個功能迥異的文檔獲取類別。範例 2-8展示了一個透過curl從遠端位址取得HTML的介面實作。
範例 2-8 HtmlDocument類別的定義
<?php class HtmlDocument implements Documentable { protected $url; public function __construct($url) { $this->url = $url; } public function getId() { return $this->url; } public function getContent() { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $this->url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); curl_setopt($ch, CURLOPT_MAXREDIRS, 3); $html = curl_exec($ch); curl_close($ch); return $html; } }
範例2-9 StreamDocument類別的定義
<?php class StreamDocument implements Documentable { protected $resource; protected $buffer; public function __construct($resource, $buffer = 4096) { $this->resource = $resource; $this->buffer = $buffer; } public function getId() { return 'resource-' . (int)$this->resource; } public function getContent() { $streamContent = ''; rewind($this->resource); while (feof($this->resource) === false) { $streamContent .= fread($this->resource, $this->buffer); } return $streamContent; } }
範例2-10 CommandDDocument類的定義範例2-11 展示了我們如何使用DocumentStore類別來操作我們實作了Documentable介面的三個文件收集類別
<?php class CommandOutputDocument implements Documentable { protected $command; public function __construct($command) { $this->command = $command; } public function getId() { return $this->command; } public function getContent() { return shell_exec($this->command); } }DocuDocucumentStore除了接口一致外其它方面完全不同。
以上就介紹了[Modern PHP] 第二章 新特性之二 基於介面的編程,包括了方面的內容,希望對PHP教程有興趣的朋友有所幫助。