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
?>
逻辑代码 45 行(超过 40 行限制,仅展示)

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 classinterface 什么时候用哪个?
A 子类之间有共享属性/逻辑(如 Shape 有 color 属性)用抽象类。完全不相关的类需要共同能力(支付、记录日志、序列化)用接口。
Q PHP 为什么不支持多继承?
A 多继承会导致"钻石问题"——两个父类有同名方法时,子类不知道用哪个。PHP 用接口 + trait 替代多继承。
Q final 类和方法有什么用?
A 防止关键逻辑被修改。比如支付计算、身份验证这类核心代码,用 final 确保子类无法重写,保证行为一致性。

📖 小节

📝 作业

  1. 创建 Vehicle 父类(brand/year/getInfo),再创建 CarMotorcycle 子类,重写 getInfo() 并在调用时用 parent::getInfo() 保留父类输出。
  2. 创建一个 Logger 接口(log(string $message): void),实现两个类 FileLogger(写文件)和 DatabaseLogger(输出到 screen),用多态统一处理日志。
  3. 创建抽象类 Employee(name/salary + 抽象方法 calculateBonus()),实现 ManagerDeveloper 子类,各自实现奖金计算逻辑。
Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏