承接上篇「PHP 類別繼承實戰」,本文深入探討 parent 關鍵字在呼叫父類別建構子與覆寫方法中的核心應用,解決子類別初始化不完整與程式碼重複問題,展示專業級物件導向設計模式。
parent 提供存取父類別的靜態引用,配合範圍解析運算子 :: 使用:
parent::__construct():呼叫父類別建構子parent::methodName():呼叫父類別任意方法上篇範例中,父類別 ShopProduct 建構子處理所有參數:
// 父類別建構子 - 違反單一職責
public function __construct($title, $firstName, $mainName, $price, $numPages=0, $playLength=0) {
// 同時處理書籍頁數與光碟播放長度
}
導致問題:
<?php
header('Content-Type: text/html; charset=utf-8');
class ShopProduct {
public $title;
public $producerMainName;
public $producerFirstName;
public $price;
public function __construct($title, $firstName, $mainName, $price) {
$this->title = $title;
$this->producerFirstName = $firstName;
$this->producerMainName = $mainName;
$this->price = $price;
}
public function getProducer() {
return "{$this->producerFirstName} {$this->producerMainName}";
}
public function getSummaryLine() {
return "{$this->title} ({$this->producerMainName}, {$this->producerFirstName})";
}
}
?>
class CdProduct extends ShopProduct {
public $playLength;
public function __construct($title, $firstName, $mainName, $price, $playLength) {
// 1. 先呼叫父類別建構子初始化共同屬性
parent::__construct($title, $firstName, $mainName, $price);
// 2. 再初始化子類別專屬屬性
$this->playLength = $playLength;
}
public function getPlayLength() {
return $this->playLength;
}
public function getSummaryLine() {
$base = parent::getSummaryLine(); // 擴展父類別方法
return "{$base}: playing time - {$this->playLength}";
}
}
class BookProduct extends ShopProduct {
public $numPages;
public function __construct($title, $firstName, $mainName, $price, $numPages) {
parent::__construct($title, $firstName, $mainName, $price);
$this->numPages = $numPages;
}
public function getNumberOfPages() {
return $this->numPages;
}
public function getSummaryLine() {
$base = parent::getSummaryLine(); // 擴展父類別方法
return "{$base}: page count - {$this->numPages}";
}
}
重構後的優勢:
// 子類別中重複的基礎摘要邏輯
$base = "{$this->title} ({$this->producerMainName}, {$this->producerFirstName})";
// 父類別:核心摘要功能
public function getSummaryLine() {
return "{$this->title} ({$this->producerMainName}, {$this->producerFirstName})";
}
// CdProduct:擴展而非重寫
public function getSummaryLine() {
$base = parent::getSummaryLine(); // 取得父類別核心結果
return "{$base}: playing time - {$this->playLength}"; // 添加專屬資訊
}
// BookProduct:同樣擴展
public function getSummaryLine() {
$base = parent::getSummaryLine();
return "{$base}: page count - {$this->numPages}";
}
abstract class BaseProduct {
// 定義演算法骨架
final public function getFullDescription() {
$summary = $this->getSummaryLine();
$details = $this->getAdditionalDetails();
return $summary . $details;
}
// 強制子類別實作
abstract protected function getAdditionalDetails();
// 可選擴展
protected function getSummaryLine() {
return "基本摘要";
}
}
class DatabaseProduct extends ShopProduct {
private $db;
public function __construct($title, $firstName, $mainName, $price, PDO $db) {
parent::__construct($title, $firstName, $mainName, $price);
$this->db = $db; // 注入依賴
}
}
| 錯誤 | 後果 | 正確做法 |
|---|---|---|
| 忘記呼叫 parent::__construct() | 父類別屬性未初始化,物件不完整 | 子類別建構子首行必須呼叫 |
| 參數順序/數量不匹配 | 嚴重錯誤或邏輯錯誤 | 嚴格對應父類別建構子簽名 |
| 覆寫方法未呼叫 parent::method() | 失去父類別核心功能 | 需擴展時主動呼叫,需完全取代則不呼叫 |
| 在建構子中呼叫可覆寫方法 | 子類別方法在父類別屬性就緒前執行 | 建構子僅初始化屬性,複雜邏輯延後 |
parent 關鍵字是 PHP 繼承機制的核心橋樑,正確使用能實現:
掌握 parent::__construct() 與 parent::method() 的應用時機與模式,是從初級邁向高級 PHP 物件導向開發的關鍵里程碑。實務上結合介面、抽象類別與設計模式,能構建高內聚、低耦合、易擴展的企業級應用架構。