class Child extends ParentClass {
// 1. 單繼承:一個類只能 extends 一個父類
// 2. 覆寫方法:同名方法會覆蓋父類,除非父類方法標記 final
// 3. 訪問父類:parent::method() / parent::$property
// 4. 構造函數:子類可擁有不同參數簽名(不受 E_STRICT 限制)
}
readonly 替代不可變屬性)。class PaymentGateway {
// 核心簽名算法,禁止子類篡改
final protected function generateSignature(array $params): string {
ksort($params);
return hash_hmac('sha256', http_build_query($params), $this->secretKey);
}
// 模板方法:固定流程,子類只能實現抽象步驟
final public function pay(float $amount): Result {
$this->validate($amount);
$signature = $this->generateSignature(['amount' => $amount]);
return $this->sendRequest($signature);
}
abstract protected function validate(float $amount): void;
abstract protected function sendRequest(string $signature): Result;
}
// class WeChatPay extends PaymentGateway { ... } // 合法
// class HackPay extends PaymentGateway {
// protected function generateSignature(...) { ... } // ❌ Fatal Error: Cannot override final method
// }
:: 稱為「範圍解析操作符」(Paamayim Nekudotayim),用於:
parent::method()ClassName::$staticProp、ClassName::CONSTANTstatic::$prop、static::method()(PHP 5.3+)ClassName::class(PHP 5.5+)class BaseController {
protected array $middleware = [];
public function __construct() {
$this->middleware = ['auth', 'log'];
}
public function execute(): void {
echo "BaseController::execute\n";
}
}
class ApiController extends BaseController {
public function __construct() {
parent::__construct(); // 必須顯式調用父構造函數
$this->middleware[] = 'rate_limit'; // 擴展而非覆蓋
}
public function execute(): void {
parent::execute(); // 調用父邏輯
echo "ApiController::execute - JSON response\n";
}
}
$ctrl = new ApiController();
$ctrl->execute();
// 輸出:
// BaseController::execute
// ApiController::execute - JSON response
這是繼承中最易踩的坑。
class ModelA {
protected static string $table = 'model_a';
public static function getTable(): string {
return self::$table; // 編譯期綁定到 ModelA
}
public static function getTableLate(): string {
return static::$table; // 運行期綁定到實際調用類
}
}
class ModelB extends ModelA {
protected static string $table = 'model_b';
}
echo ModelA::getTable(); // model_a
echo ModelB::getTable(); // model_a ❌ 期望 model_b
echo ModelA::getTableLate(); // model_a
echo ModelB::getTableLate(); // model_b ✅ 正確
規則: 靜態屬性/方法若需多態行為,**必須用 static::(晚期靜態綁定 LSB)**;self:: 永遠指向定義該代碼的類。
| 場景 | 規則 | 違反後果 |
|---|---|---|
| 普通方法覆寫 | 參數數量、類型、順序**必須兼容**(逆變/協變) | PHP 7.0+ 拋 E_WARNING / 8.0+ TypeError |
| 返回類型 | 子類返回類型應為父類返回類型的**子類型**(協變) | 同左 |
| 構造函數 | **例外**:參數可完全不同 | 無錯誤,但違反 LSP 設計應避免 |
| private 方法 | 不參與繼承,子類同名方法視為新方法 | 無覆寫關係,互不影響 |
| final 方法/類 | 禁止覆寫/繼承 | Fatal Error |
雖非 extends,但常配合使用。同名方法衝突時用 insteadof 與 as:
trait Loggable { public function log(string $msg) { echo "[LOG] $msg\n"; } }
trait Debuggable { public function log(string $msg) { echo "[DEBUG] $msg\n"; } }
class Service {
use Loggable, Debuggable {
Debuggable::log insteadof Loggable; // 選用 Debug 版
Loggable::log as logToFile; // 別名保留 Log 版
}
}
$svc = new Service();
$svc->log('hello'); // [DEBUG] hello
$svc->logToFile('file'); // [LOG] file
parent::?遺漏導致父類初始化邏輯缺失。static::?避免 self:: 導致多態失效。final 封閉關鍵邏輯?防止意外覆寫。extends 是雙刃劍:用好能構建清晰的「是一種」層次結構,用錯則產生脆弱的強耦合。**記住三原則:1) 單一職責,父類只做一件事;2) 開閉原則,對擴展開放(非 final)、對修改關閉(final 保護核心);3) 里氏替換,子類能無縫替換父類。** 遇到「想繼承只為復用代碼」時,請改用 Trait 或組合。