前言
本文為《現代 PHP》一書的學習筆記。
環境
介面
介面(Interface)是一個介於兩個 PHP 物件之間的合約,讓一個物件了解另一個物件「可以做什麼」。
介面的例子如下:
1 2 3 4
   | interface MyInterface {      }
   | 
 
假想一個 DocumentStore 類別,它用來蒐集來自不同來源的文字:從遠端 URL 擷取的 HTML、讀取串流來源,以及終端機指令的輸出。
範例 2-6:DocumentStore 類別定義
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
   | 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;      } }
   | 
 
addDocument() 方法只接受 Documentable 的實例。 
範例 2-7:Documentable 介面定義
1 2 3 4 5 6
   | interface Documentable {     public function getId();
      public function getContent(); }
   | 
 
- 介面定義了任何實作 
Documentable 介面的物件都必須提供公開的 getId() 和 getContent() 方法。 
範例 2-8:HtmlDocument 類別定義
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
   | 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;     } }
   | 
 
curl_init() 函數用來初始化 cURL 會話 
curl_setopt() 函數用來設置 cURL 傳輸選項 
curl_exec() 函數用來執行 cURL 會話 
curl_close() 函數用來關閉 cURL 會話 
範例 2-9:StreamDocument 類別定義
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
   | 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;     } }
   | 
 
rewind() 函數用來使文件指針的位置回到文件的開頭。 
feof() 函數用來檢測是否已到達文件末尾。 
fread() 函數用來讀取文件,第二個參數是讀取的最大位元數。 
範例 2-10:CommandOutputDocument 類別定義
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
   | 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);     } }
   | 
 
shell_exec() 函式用來通過 Shell 環境執行命令,並以字串返回完整輸出。 
範例 2-11:蒐集來自不同來源的文字
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
   | require 'Documentable.php'; require 'DocumentStore.php'; require 'HtmlDocument.php'; require 'StreamDocument.php'; require 'CommandOutputDocument.php';
  $documentStore = new DocumentStore();
 
  $htmlDoc = new HtmlDocument('http://php.net'); $documentStore->addDocument($htmlDoc);
 
  $streamDoc = new StreamDocument(fopen('stream.txt', 'rb'));  $documentStore->addDocument($streamDoc);
 
  $cmdDoc = new CommandOutputDocument('echo hello world!'); $documentStore->addDocument($cmdDoc);
  print_r($documentStore->getDocuments());
   | 
 
類別與介面之間的關係如下:
| 類別 | 
方法 | 
介面 | 
類別 | 
| DocumentStore | 
addDocument() | 
Documentable | 
HtmlDocument | 
 | 
 | 
 | 
StreamDocument | 
 | 
 | 
 | 
CommandOutputDocument | 
| 用來蒐集不同來源的文字 | 
僅接受實作介面的實例 | 
定義實作介面的物件必須提供的方法 | 
使用 implements 關鍵字實作介面 | 
參考資料
- Josh Lockhart(2015)。現代 PHP。台北市:碁峯資訊。