PHP 繼承 (Inheritance)
繼承讓類別可以繼承另一個類別的屬性和方法,實現程式碼重用和建立類別層級結構。
基本繼承
使用 extends 關鍵字繼承類別:
<?php
class Animal {
public string $name;
public function __construct(string $name) {
$this->name = $name;
}
public function speak(): string {
return "...";
}
}
class Dog extends Animal {
public function speak(): string {
return "Woof!";
}
}
class Cat extends Animal {
public function speak(): string {
return "Meow!";
}
}
$dog = new Dog("Buddy");
echo $dog->name; // Buddy
echo $dog->speak(); // Woof!
?>
parent 關鍵字
使用 parent:: 呼叫父類別的方法:
<?php
class Animal {
public function __construct(
public string $name
) {}
public function describe(): string {
return "這是 {$this->name}";
}
}
class Dog extends Animal {
public function __construct(
string $name,
public string $breed
) {
parent::__construct($name);
}
public function describe(): string {
return parent::describe() . ",品種是 {$this->breed}";
}
}
$dog = new Dog("Buddy", "Golden Retriever");
echo $dog->describe();
// 這是 Buddy,品種是 Golden Retriever
?>
方法覆寫 (Override)
子類別可以覆寫父類別的方法:
<?php
class Shape {
public function area(): float {
return 0;
}
}
class Rectangle extends Shape {
public function __construct(
public float $width,
public float $height
) {}
public function area(): float {
return $this->width * $this->height;
}
}
class Circle extends Shape {
public function __construct(
public float $radius
) {}
public function area(): float {
return M_PI * $this->radius ** 2;
}
}
$rect = new Rectangle(5, 3);
echo $rect->area(); // 15
$circle = new Circle(5);
echo $circle->area(); // 78.54...
?>
final 關鍵字
final 可以防止類別被繼承或方法被覆寫:
<?php
// final 類別不能被繼承
final class Singleton {
private static ?self $instance = null;
private function __construct() {}
public static function getInstance(): self {
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
}
// final 方法不能被覆寫
class Base {
final public function important(): void {
echo "這個方法不能被覆寫";
}
}
class Child extends Base {
// public function important(): void {} // 錯誤!
}
?>
protected 修飾符
protected 成員可以在類別內和子類別中存取:
<?php
class Animal {
protected string $type = 'Unknown';
protected function getType(): string {
return $this->type;
}
}
class Dog extends Animal {
public function __construct() {
$this->type = 'Dog'; // 可以存取 protected
}
public function showType(): string {
return $this->getType(); // 可以呼叫 protected 方法
}
}
$dog = new Dog();
echo $dog->showType(); // Dog
// echo $dog->type; // 錯誤:外部無法存取 protected
?>
多型 (Polymorphism)
<?php
class Animal {
public function speak(): string {
return "...";
}
}
class Dog extends Animal {
public function speak(): string {
return "Woof!";
}
}
class Cat extends Animal {
public function speak(): string {
return "Meow!";
}
}
function makeAnimalSpeak(Animal $animal): void {
echo $animal->speak() . "\n";
}
$animals = [new Dog(), new Cat(), new Animal()];
foreach ($animals as $animal) {
makeAnimalSpeak($animal);
}
// Woof!
// Meow!
// ...
?>
繼承與建構子
<?php
class Person {
public function __construct(
public string $name,
public int $age
) {}
}
class Employee extends Person {
public function __construct(
string $name,
int $age,
public string $department,
public float $salary
) {
parent::__construct($name, $age);
}
}
$employee = new Employee("Alice", 30, "IT", 50000);
echo $employee->name; // Alice
echo $employee->department; // IT
?>
檢查類別關係
<?php
class Animal {}
class Dog extends Animal {}
$dog = new Dog();
// instanceof 檢查
var_dump($dog instanceof Dog); // true
var_dump($dog instanceof Animal); // true
// get_class 取得類別名稱
echo get_class($dog); // Dog
// get_parent_class 取得父類別
echo get_parent_class($dog); // Animal
// is_a 函數
var_dump(is_a($dog, 'Animal')); // true
?>
實際範例
<?php
class Logger {
public function log(string $message): void {
echo "[" . date('Y-m-d H:i:s') . "] $message\n";
}
}
class FileLogger extends Logger {
public function __construct(
private string $filename
) {}
public function log(string $message): void {
$formatted = "[" . date('Y-m-d H:i:s') . "] $message\n";
file_put_contents($this->filename, $formatted, FILE_APPEND);
}
}
class DatabaseLogger extends Logger {
public function __construct(
private PDO $db
) {}
public function log(string $message): void {
$stmt = $this->db->prepare(
"INSERT INTO logs (message, created_at) VALUES (?, NOW())"
);
$stmt->execute([$message]);
}
}
function processData(Logger $logger): void {
$logger->log("開始處理");
// ... 處理邏輯
$logger->log("處理完成");
}
?>