PHP: 继承与多态
继承是 OOP 的核心——"学生是用户的一种","猫是动物的一种"。父类定义通用行为,子类扩展和特化。多态让你用统一接口处理不同类型对象。
1. extends — 继承
PHP
<?php
// 父类(基类)
class Animal {
public function __construct(
public string $name
) {}
public function speak(): string {
return "{$this->name} 发出声音";
}
public function sleep(): string {
return "{$this->name} 在睡觉";
}
}
// 子类继承父类
class Dog extends Animal {
// 重写父类方法
public function speak(): string {
return "{$this->name}:汪汪!";
}
// 新增方法
public function fetch(): string {
return "{$this->name} 去捡球了";
}
}
class Cat extends Animal {
public function speak(): string {
return "{$this->name}:喵喵~";
}
}
$dog = new Dog("大黄");
echo $dog->speak(); // 大黄:汪汪!(重写的方法)
echo $dog->sleep(); // 大黄 在睡觉(继承的方法)
echo $dog->fetch(); // 大黄 去捡球了(新增的方法)
$cat = new Cat("小花");
echo $cat->speak(); // 小花:喵喵~(重写的方法)
echo $cat->sleep(); // 小花 在睡觉(继承的方法)
?>
💡 提示: PHP 是单继承——一个类只能
extends 一个父类。多继承的能力通过 trait 和接口实现(后续课程会讲)。
2. parent — 调用父类方法
子类重写方法时,如果还想用父类原本的逻辑,用 parent:::
PHP
<?php
class Vehicle {
public function __construct(
public string $brand,
public int $year
) {}
public function getInfo(): string {
return "{$this->year}款 {$this->brand}";
}
}
class ElectricCar extends Vehicle {
public function __construct(
string $brand,
int $year,
public int $batteryRange // 电动车的额外属性
) {
// 调用父类构造函数
parent::__construct($brand, $year);
}
// 重写并扩展父类方法
public function getInfo(): string {
return parent::getInfo() . " 电动车(续航{$this->batteryRange}km)";
}
}
$car = new ElectricCar("特斯拉", 2026, 600);
echo $car->getInfo(); // 2026款 特斯拉 电动车(续航600km)
?>
3. final — 禁止继承/重写
PHP
<?php
class Template {
// 算法骨架,不允许子类修改
final public function render(): string {
$html = $this->header();
$html .= $this->body();
$html .= $this->footer();
return $html;
}
protected function header(): string {
return "<header>默认头部</header>";
}
protected function body(): string {
return "<main>默认内容</main>";
}
protected function footer(): string {
return "<footer>默认底部</footer>";
}
}
// ✅ 子类可以重写 header/body/footer
class BlogTemplate extends Template {
protected function header(): string {
return "<header>博客标题</header>";
}
// ❌ 但不能重写 render()——被 final 保护
// public function render(): string { ... }
}
?>
4. instanceof — 类型检查
PHP
<?php
function makeSound(Animal $animal): string {
if ($animal instanceof Dog) {
return $animal->speak() . "(好狗!)";
} elseif ($animal instanceof Cat) {
return $animal->speak() . "(可爱!)";
}
return $animal->speak();
}
echo makeSound(new Dog("大黄")); // 大黄:汪汪!(好狗!)
echo makeSound(new Cat("小花")); // 小花:喵喵~(可爱!)
?>
5. 抽象类(abstract)
抽象类不能被直接实例化——它的作用是定义"子类应该长什么样":
▶ 示例:Shape 抽象类体系
PHP
📖 仅展示
<?php
abstract class Shape {
public function __construct(
protected string $color = "黑色"
) {}
// 抽象方法:子类必须实现
abstract public function area(): float;
abstract public function perimeter(): float;
// 普通方法:子类可以继承或重写
public function describe(): string {
return "{$this->color}的图形,面积:" . round($this->area(), 2);
}
}
class Circle extends Shape {
public function __construct(
private float $radius,
string $color = "黑色"
) {
parent::__construct($color);
}
public function area(): float {
return pi() * pow($this->radius, 2);
}
public function perimeter(): float {
return 2 * pi() * $this->radius;
}
}
class Rectangle extends Shape {
public function __construct(
private float $width,
private float $height,
string $color = "黑色"
) {
parent::__construct($color);
}
public function area(): float {
return $this->width * $this->height;
}
public function perimeter(): float {
return 2 * ($this->width + $this->height);
}
}
// $s = new Shape("红色"); // ❌ 抽象类不能实例化
$c = new Circle(5, "红色");
echo $c->describe(); // 红色的图形,面积:78.54
$r = new Rectangle(4, 6, "蓝色");
echo $r->describe(); // 蓝色的图形,面积:24
?>
6. 接口(interface)
接口定义"能做什么"的契约,不定义"怎么做":
PHP
<?php
interface Payable {
public function getAmount(): float;
public function pay(): string;
}
interface Refundable {
public function refund(): string;
}
// 一个类可以实现多个接口
class CreditCard implements Payable, Refundable {
public function __construct(
private string $cardNumber,
private float $amount
) {}
public function getAmount(): float {
return $this->amount;
}
public function pay(): string {
return "信用卡 {$this->cardNumber} 支付 {$this->amount} 元";
}
public function refund(): string {
return "退还 {$this->amount} 元到信用卡 {$this->cardNumber}";
}
}
class Crypto implements Payable {
public function __construct(
private float $amount
) {}
public function getAmount(): float {
return $this->amount;
}
public function pay(): string {
return "加密货币支付 {$this->amount} 元";
}
// Crypto 不支持退款——不实现 Refundable 接口
}
?>
7. 多态(Polymorphism)的实际应用
多态的核心:用统一的父类/接口类型处理不同的子类对象:
▶ 示例:多态支付系统
PHP
<?php
class PaymentProcessor {
/**
* 用多态处理支付——不管是什么支付方式
*/
public function process(Payable $payment): void {
echo "【支付】{$payment->pay()}<br>";
// 有些支付方式支持退款
if ($payment instanceof Refundable) {
echo "【退款支持】{$payment->refund()}<br>";
}
}
/**
* 批量结算——因为都实现了 Payable,可以统一处理
*/
public function settle(array $payments): float {
$total = 0;
foreach ($payments as $payment) {
$total += $payment->getAmount();
echo $payment->pay() . "<br>";
}
echo "总金额:{$total} 元<br>";
return $total;
}
}
$processor = new PaymentProcessor();
// 多态——调用方不知道具体是什么支付方式
$processor->settle([
new CreditCard("1234-5678", 199.00),
new Crypto(0.05),
new CreditCard("8765-4321", 59.99),
]);
?>
| 特性 | abstract class | interface |
|---|---|---|
| 可以有属性 | ✅ | ❌ |
| 可以有已实现的方法 | ✅ | ❌(PHP 8+ 可以有默认方法) |
| 可以有常量 | ✅ | ✅ |
| 可以多继承 | ❌(单继承) | ✅(多接口实现) |
| 用于 | "是什么"(is-a) | "能做什么"(can-do) |
💡 提示: 选择原则:子类之间有强逻辑关联用抽象类(Shape→Circle),不相关的类需要共同能力用接口(CreditCard/Crypto→Payable)。
❓ 常见问题
Q
abstract class 和 interface 什么时候用哪个?A 子类之间有共享属性/逻辑(如 Shape 有 color 属性)用抽象类。完全不相关的类需要共同能力(支付、记录日志、序列化)用接口。
Q PHP 为什么不支持多继承?
A 多继承会导致"钻石问题"——两个父类有同名方法时,子类不知道用哪个。PHP 用接口 + trait 替代多继承。
Q
final 类和方法有什么用?A 防止关键逻辑被修改。比如支付计算、身份验证这类核心代码,用
final 确保子类无法重写,保证行为一致性。📖 小节
extends继承父类所有 public/protected 的属性和方法parent::调用父类被重写的方法final禁止类被继承或方法被重写instanceof检查对象是不是某个类的实例- 抽象类:定义"家族模板",强迫子类实现 abstract 方法
- 接口:定义"能力契约",一个类可实现多个接口
- 多态:用父类/接口类型统一操作不同子类对象
📝 作业
- 创建
Vehicle父类(brand/year/getInfo),再创建Car和Motorcycle子类,重写getInfo()并在调用时用parent::getInfo()保留父类输出。 - 创建一个
Logger接口(log(string $message): void),实现两个类FileLogger(写文件)和DatabaseLogger(输出到 screen),用多态统一处理日志。 - 创建抽象类
Employee(name/salary + 抽象方法calculateBonus()),实现Manager和Developer子类,各自实现奖金计算逻辑。