繼承是 OOP 實現程式碼重用與多型的核心機制。透過 extends 關鍵字,子類別自動擁有父類別的非私有成員,並可新增或覆寫功能。本文以 User/Admin 角色系統為例,詳細說明繼承語法、存取規則與實務應用。
<?php
// 父類別(基底類別)
class User {
private string $name = '';
public function __construct(array $attribs = []) {
$this->name = $attribs['name'] ?? '';
}
public function getName(): string {
return $this->name;
}
}
// 子類別繼承父類別
class Admin extends User {
// 新增父類別沒有的功能
public function getAdmin(): string {
return 'Administrator';
}
}
// 使用
$kirupa = new Admin(['name' => 'Kirupa']);
echo $kirupa->getName() . '<br />'; // Kirupa(繼承自 User)
echo $kirupa->getAdmin(); // Administrator(Admin 專有)
$regular = new User(['name' => 'Regular']);
echo $regular->getName(); // Regular
// $regular->getAdmin(); // 錯誤:User 沒有此方法
?>
| 父類別成員可見性 | 子類別內部 | 外部程式碼 | 說明 |
|---|---|---|---|
public |
✅ 可存取 | ✅ 可存取 | 完全公開 |
protected |
✅ 可存取 | ❌ 不可存取 | 供子類別擴充 |
private |
❌ 不可直接存取 | ❌ 不可存取 | 僅父類別內部,子類別需透過 public/protected 方法 |
<?php
class Admin extends User {
// 封鎖使用者
public function banUser(int $userId): bool {
// 實作封鎖邏輯...
return true;
}
// 解封使用者
public function unbanUser(int $userId): bool {
// 實作解封邏輯...
return true;
}
// 刪除內容
public function deleteContent(int $contentId): bool {
// 實作刪除邏輯...
return true;
}
// 查看系統日誌
public function viewSystemLogs(): array {
// 實作日誌查詢...
return [];
}
}
?>
PHP 採用單一繼承模型:一個類別只能繼承一個父類別。
<?php
// 錯誤:PHP 不支援多重繼承
// class SuperAdmin extends User, Admin { } // Fatal error
// 替代方案:介面 + Trait
interface AdminInterface {
public function banUser(int $userId): bool;
}
trait AdminTraits {
public function banUser(int $userId): bool { /* ... */ }
public function unbanUser(int $userId): bool { /* ... */ }
}
class SuperAdmin extends User {
use AdminTraits; // 組合功能
implements AdminInterface; // 契約約束
}
?>
子類別可重新定義父類別方法,改變行為:
<?php
class User {
public function getRole(): string {
return 'User';
}
}
class Admin extends User {
// 覆寫父類別方法
public function getRole(): string {
return 'Administrator';
}
// 仍可呼叫父類別版本
public function getParentRole(): string {
return parent::getRole(); // 呼叫 User::getRole()
}
}
?>
<?php
// 禁止被繼承
final class Config {
// ...
}
// 禁止方法被覆寫
class BaseService {
final protected function connectDatabase(): void {
// 核心連線邏輯,不允許子類別修改
}
}
?>
<?php
class User {
public function __construct(protected string $name) {}
}
class Admin extends User {
// 子類別若定義建構子,必須主動呼叫 parent::__construct()
public function __construct(string $name, private string $permissionLevel) {
parent::__construct($name); // 必須顯式呼叫
}
}
?>
| 場景 | 推薦方式 | 理由 |
|---|---|---|
| 子類別真的是父類別的特化型態 | 繼承 | 語意正確、自然符合 Liskov 替換原則 |
| 只需複用部分功能 | Trait / 組合 | 避免繼承層級過深、減少耦合 |
| 需在執行時動態切換行為 | 策略模式(組合) | 繼承為靜態結構,無法動態變更 |
| 多個類別需共享相同功能 | Trait / 服務類別 | 避免建立虛假的繼承關係 |