摘要訊息 : 學習 PHP 中的介面.
0. 前言
假設現在有一個 PHP 需求 : 有兩個完全不同的類別, 但是這兩個類別 A、B 都有一個共同名稱的方法 C, 只是方法的實作方式不同. 現在有一個函式, 可能呼叫類別 A 的 C 方法, 也可能呼叫 B 的 C 方法. 如果要去實現這個函式, 那麼可能需要寫兩個不同的函式. 但是如果我想要簡單地用一個函式去實現, 應該如何做呢? 於是, 這就用到了 PHP 的一個特性 - 介面.
正式介紹之前, 我們要用一個例子, 將抽象的介面模型化, 這也就是之前介紹過的編程模型, 這有利於任何人去理解介面.
現在我們要生產一部手機. 那麼, 顯示器、電池、CPU、記憶體等組成了一部手機. 一部手機必須要有這些零件, 否則將無法組成一部手機. 但是這些零件可以各有不同, 相互毫無關係. 例如顯示器, 它可以是任何供應商以不同的生產方式生產的, 只要在兼容並蓄的情況下, 它可以是任何手機的顯示器. 反之來說, 任何手機都可以用這個顯示器作為零件. 如果將這個模型轉化為程式設計, 那麼手機就是一個類別, 那些顯示器、電池、CPU 等的零部件就是類別內的方法, 如果不能實現這些方法, 或者沒有這些方法, 將無法組成這部手機, 這些方法抽象化後被定義為介面. 方法的實作方式可以不同 (也就是生產方法和生產廠商可以是不同的), 但是最後都被用於實現一部手機 (類別被實例化), 不管手機是什麼樣子的, 有什麼功能. 換句話說, 任何手機都可以用顯示器這個方法實現一些功能 (介面的呼叫).
如果你已經對介面有了概念上的了解, 那麼可以正式開始學習並且使用介面了.
本文於 2022 年 3 月 18 日進行一次更新和修正. 修正之後本文已經歸檔, 不再享受更新.
1. 介面基礎
介面在 PHP 中有兩個關鍵字 : interface
和 implements
. 它的宣告方式和類別是相似的. 只是類別使用 class
來宣告, 介面使用 interface
來宣告. 介面可以擁有常數成員, 抽象方法 :
<?php
interface itf {
const BUFFER = 2048;
public function func();
}
類別支援實作多個介面 :
<?php
interface itf {}
interface itf_2 {}
class foo implements itf, itf_2 {}
介面支援從另外一個介面衍生 :
<?php
interface itf {}
interface itf_ext extends itf {}
但是我們不可以在介面中宣告屬性成員. 介面也不可以被實例化. 介面中的方法不可以被實作, 只能是抽象的方法.
關於介面的介紹, 就到這裡, 下面我們通過一個實例來學習使用介面.
這個實例中, 實現了 people
介面, people
類別, teacher
類別和 student
類別. 其中, people
, teacher
和 student
類別都是以 people
介面為基礎, 並且 teacher
類別和 student
類別都是
people 類別的衍生 :
<?php
interface people_interface {
public function insert_name($name);
public function insert_gender($gender);
public function get_name();
public function get_gender();
}
class people implements people_interface {
protected $name;
protected $gender;
public function insert_name($name) {
$this->name = $name;
}
public function insert_gender($gender) {
$this->gender = $gender;
}
public function get_name() {
return $this->name;
}
public function get_gender() {
return $this->gender;
}
}
class student extends people implements people_interface {
protected $id;
private $data;
public function insert_id($id) {
$this->id = $id;
}
public function get_id() {
return $this->id;
}
public function insert(people_interface $people) {
$this->data = $people->get_name()." : ".$people->get_gender();
}
public function get_data() {
return $this->data;
}
}
class teacher extends people implements people_interface {
protected $subject;
public function get_name() {
return $this->name." : ".$this->subject;
}
public function insert_subject($subject) {
$this->subject = $subject;
}
public function get_subject() {
return $this->subject;
}
}
$t = new teacher();
$t->insert_name("Jack");
$t->insert_subject("math");
$t->insert_gender("F");
$p = new people();
$p->insert_name("Amy");
$p->insert_gender("M");
$s = new student();
$s->insert($teacher);
echo $s->getData();
echo "\n";
$s->insert($people);
echo $s->get_data();
/* 結果 :
Jack : math : F
Amy : M
*/
從上面這個實例可以看到, 介面中的抽象方法必須在類別中被實作, 否則就會出現錯誤.
我們特別注意到 student
類別中的 insert
, 它的引數中有一個 people_interface
, 也就是 people
的介面. 我們看到實際在呼叫 student
的 insert
的時候, 引數是一個類別. 這個方法被呼叫了兩次, 第一次放入的是 $t
, 第二次放入的是 $p
. 實際 insert 方法裡面呼叫了介面中存在的兩個抽象方法, get_name
和 get_gender
方法. 也就是說, 只要一個類別使用了 people_interface
介面, 那麼就可以成為 insert
方法的引數.
介面的實際用途是很難用言語去表達清楚的, 如果你不是很明白的話, 建議你看完上面這段之後, 重新回到第一段去看看那個疑問. 這之後, 你再回來看看這段話, 也許你就會有所感悟.
總而言之, 使用介面可以讓 PHP 編程更加靈活, 也可以減少一些重複的代碼. 而且, 你可能還可以通過介面委託他人幫你實現一些功能. 使用介面之後, 別人只要知道如何使用介面, 就可以無縫地使用你的程式碼.
自創文章, 原著 : Jonny. 如若閣下需要轉發, 在已經授權的情況下請註明本文出處 :