介面與抽象類都是實現多型與規範契約的工具,但設計意圖、語法限制、適用場景有本質不同。本文深度解析兩者異同並提供選擇決策指南。
abstract class 宣告<?php
abstract class Animal {
// 屬性
protected $name;
protected $age = 0;
public const TYPE = 'animal';
// 具體方法(預設實作)
public function breathe() {
echo "{$this->name} 在呼吸...\n";
}
// 抽象方法(強制子類實作)
abstract protected function makeSound();
abstract public function move();
}
abstract class Mammal extends Animal {
// 部分實作抽象方法
public function makeSound() {
echo "哺乳類發聲...\n";
}
// move() 仍為抽象,Mammal 仍為抽象類
}
class Dog extends Mammal {
public function __construct($name) {
$this->name = $name;
}
// 必須實作所有剩餘抽象方法
public function move() {
echo "{$this->name} 用四條腿跑動\n";
}
}
$dog = new Dog('旺財');
$dog->breathe(); // 繼承具體方法
$dog->makeSound(); // 繼承中間類實作
$dog->move(); // 自身實作
interface 宣告implements 實作介面<?php
interface Flyable {
public const MAX_HEIGHT = 10000;
public function fly();
public function land();
}
interface Swimmable {
public function swim();
}
class Duck implements Flyable, Swimmable {
public function fly() {
echo "鴨子飛行中... (高度 < " . Flyable::MAX_HEIGHT . "m)\n";
}
public function land() { echo "鴨子降落\n"; }
public function swim() { echo "鴨子游泳\n"; }
}
// 介面可繼承多個介面
interface FlyableAndSwimmable extends Flyable, Swimmable {}
| 特性 | 抽象類 | 介面 |
|---|---|---|
| 關鍵字 | extends | implements |
| 多重實作 | 單一繼承 | 可實作多個 |
| 方法類型 | 抽象 + 具體 | 全部抽象 (PHP 8.0 前) |
| 屬性/狀態 | ✅ 可定義 | ❌ 僅常數 |
| 建構子 | ✅ 可定義 | ❌ 不可 |
| 存取修飾子 | public/protected/private | 僅 public |
| 設計意圖 | 「是一種」關係、共享代碼/狀態 | 「能做某事」能力、契約規範 |
<?php
interface Logger {
public function log(string $message);
// PHP 8.0+ 介面可有預設方法實作
public function logInfo(string $message) {
$this->log("[INFO] $message");
}
public function logError(string $message) {
$this->log("[ERROR] $message");
}
}
使用抽象類當:
- 需要共享代碼/狀態(屬性、建構子、預設方法)
- 建立「是一種」關係(Dog 是 Animal)
- 需要非 public 的抽象方法
- 需要定義建構子強制初始化邏輯
使用介面當:
- 定義「能做某事」的能力契約
- 類別需要實作多個不相關契約
- 無需共享狀態,純行為規範
- 第三方庫擴展(不想強制繼承特定基類)
組合使用: 抽象類實作介面,子類繼承抽象類
<?php
// 契約:支付能力
interface Payable {
public function pay(float $amount): bool;
public function refund(string $transactionId): bool;
}
// 共享邏輯:記錄、驗證
abstract class BasePayment implements Payable {
protected $logger;
protected $config;
public function __construct(Logger $logger, array $config) {
$this->logger = $logger;
$this->config = $config;
}
// 模板方法:共享流程
public function pay(float $amount): bool {
if (!$this->validateAmount($amount)) return false;
$result = $this->doPay($amount);
$this->logger->log("Payment {$result ? 'success' : 'failed'}: $amount");
return $result;
}
abstract protected function doPay(float $amount): bool;
abstract protected function validateAmount(float $amount): bool;
}
// 具體實作
class AlipayPayment extends BasePayment {
protected function doPay(float $amount): bool { /* ... */ }
protected function validateAmount(float $amount): bool { /* ... */ }
}
class WechatPayment extends BasePayment {
protected function doPay(float $amount): bool { /* ... */ }
protected function validateAmount(float $amount): bool { /* ... */ }
}