抽象類核心規則
- 至少包含一個抽象方法(無方法體)
- 不能被實例化(`new AbstractClass()` 報錯)
- 可被繼承,子類必須實現所有抽象方法(除非子類也是抽象類)
- 可包含具體方法、屬性、常量
- 支援多層抽象繼承鏈
代碼示例
";
}
}
// 子抽象類:繼承並新增抽象方法
abstract class Jj extends Qian {
abstract public function getThree();
}
// 具體實現類
class Nan extends Jj {
public function getFirst() {
echo "I am getFirst
";
}
public function getThree() {
echo "I am getThree
";
}
}
// 使用
$nn = new Nan();
$nn->getFirst(); // I am getFirst
$nn->getTwo(); // I am getTwo (繼承自 Qian)
$nn->getThree(); // I am getThree
抽象類 vs 介面 對比
| 特性 | 抽象類 | 介面 |
| 關鍵字 | abstract class | interface |
| 方法實現 | 可包含具體方法 | 全部為抽象方法 (PHP 8.0 前) |
| 屬性 | 可定義屬性(含可見性) | 只能定義常量 |
| 繼承關係 | 單繼承 (extends) | 多實現 (implements) |
| 構造函數 | 可定義 | 不可定義 |
| 靜態成員 | 支援 | 支援 |
| 適用場景 | "是一種"關係、共享代碼 | "能夠做"契約、多態 |
實戰模式:模板方法模式
abstract class DataExporter {
// 模板方法:定義算法骨架
final public function export(array $data, string $file) {
$header = $this->generateHeader();
$body = $this->formatData($data);
$footer = $this->generateFooter();
file_put_contents($file, $header . $body . $footer);
}
// 鉤子方法:子類可選覆蓋
protected function generateHeader(): string { return ''; }
protected function generateFooter(): string { return ''; }
// 抽象方法:子類必須實現
abstract protected function formatData(array $data): string;
}
class CsvExporter extends DataExporter {
protected function formatData(array $data): string {
return implode("\n", array_map(fn($row) => implode(',', $row), $data));
}
}
class JsonExporter extends DataExporter {
protected function formatData(array $data): string {
return json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
}
protected function generateHeader(): string { return "// Export at " . date('c') . "\n"; }
}
// 使用
$exporter = new CsvExporter();
$exporter->export([['a',1],['b',2]], 'data.csv');
常見錯誤與最佳實踐
| 錯誤 | 正確做法 |
| 抽象方法有方法體 | 抽象方法僅聲明,無 `{}` |
| 實例化抽象類 | 實例化具體子類 |
| 子類未實現所有抽象方法 | 全部實現或聲明為抽象類 |
| 私有抽象方法 | 抽象方法必須 `public` 或 `protected` |
| 過度使用繼承 | 優先組合/介面,抽象類用於緊密相關類層次 |
總結
抽象類是「不完整的類」,定義了子類必須遵循的契約與共享邏輯。良好的設計原則:介面定義契約,抽象類實現共享邏輯,具體類提供具體實現。理解抽象類與介面的區別,能構建更靈活、可擴展的系統架構。