使用介面(interface),可以指定某個類必須實現哪些方法,但不需要定義這些方法的具體內容。由於介面(interface)和類(class)、trait 共享了命名空間,所以它們不能重名。介面就像定義一個標準的類一樣,通過 interface 關鍵字替換掉 class 關鍵字來定義,但其中所有的方法都是空的。介面中定義的所有方法都必須是公有,這是介面的特性。在實踐中,往往出於兩個輔助目的使用介面: 因為實現了同一個介面,所以開發者創建的對象雖然源自不同的類,但可能可以交換使用。常用於多個數據庫的服務訪問、多個支付網關、不同的緩存策略等。可能不需要任何代碼修改,就能切換不同的實現方式。能夠讓函數與方法接受一個符合介面的參數,而不需要關心對像如何做、如何實現。這些介面常常命名成類似 Iterable、Cacheable、Renderable, 以便於體現出功能的含義。
注意: 雖然沒有禁止,但是強烈建議不要在接口中使用 構造器。因為這樣在對象實現接口時,會大幅降低靈活性。此外,也不能強制確保構造器遵守繼承規則,將導致不可預料的行為結果。
要使用一個介面,使用 implements 操作符。類中必須使用介面中定義的所有方法,否則會報一個致命錯誤。類可以實現多個接口,用逗號來分隔多個接口的名稱。
警告:類使用(implement)兩個接口時,如果它們定義了相同名稱的方法,只有簽名相同的時候才是允許的。
警告:使用介面的時候,class 中的參數名稱不必和介面完全一致。然而, PHP 8.0 起語法開始支持命名參數, 也就是說調用方會依賴介面中參數的名稱。因此,強烈建議開發者的參數的命名,在類和介面中保持一致。
注意:接口也可以通過 extends 操作符繼承
注意:類實現介面時,必須以兼容的簽名定義介面中所有方法。
<?php
// 聲明一個'Template'介面
interface Template
{
public function setVariable($name, $var);
public function getHtml($template);
}
// 使用介面
// 正確寫法如下
class WorkingTemplate implements Template
{
private $vars = [];
public function setVariable($name, $var)
{
$this->vars[$name] = $var;
}
public function getHtml($template)
{
foreach($this->vars as $name => $value) {
$template = str_replace('{' . $name . '}', $value, $template);
}
return $template;
}
}
// 下面的寫法是錯誤的,會報錯,因為沒有使用到該介面方法 getHtml():
// Fatal error: Class BadTemplate contains 1 abstract methods
// and must therefore be declared abstract (Template::getHtml)
class BadTemplate implements Template
{
private $vars = [];
public function setVariable($name, $var)
{
$this->vars[$name] = $var;
}
}
?>
<?php
interface A
{
public function foo();
}
interface B extends A
{
public function baz(Baz $baz);
}
// 正確寫法
class C implements B
{
public function foo()
{
}
public function baz(Baz $baz)
{
}
}
// 錯誤寫法導致致命錯誤
class D implements B
{
public function foo()
{
}
public function baz(Foo $foo) // 參考錯誤
{
}
}
?>
<?php
interface A
{
public function foo();
}
interface B
{
public function bar();
}
interface C extends A, B
{
public function baz();
}
class D implements C
{
public function foo()
{
}
public function bar()
{
}
public function baz()
{
}
}
?>
<?php
interface A
{
const B = 'Interface constant';
}
// 输出接口常量
echo A::B;
// 錯誤寫法,因為常量不能被覆蓋。接口常量的概念和類常量是一樣的。
class B implements A
{
const B = 'Class constant';
}
?>
<?php
interface A
{
public function foo(string $s): string;
public function bar(int $i): int;
}
// 抽象類可能僅實現了接口的一部分。
// 擴展該抽象類時必須實現剩餘部分
abstract class B implements A
{
pubic function foo(string $s): string
{
return $s . PHP_EOL;
}
}
class C extends B
{
public function bar(int $i): int
{
return $i * 2;
}
}
?>
<?php
class One
{
/* ... */
}
interface Usable
{
/* ... */
}
interface Updatable
{
/* ... */
}
// 關鍵字順序至關重要: 'extends' 必須在前面
class Two extends One implements Usable, Updatable
{
/* ... */
}
?>
資料來源: https://www.php.net/