Menu
CoddyTech

接口与抽象类

本课属于 Coddy PHP 学习旅程的“面向对象编程”单元。第 30 课,共 91 课。

现在你已经学习了接口和抽象类,接下来我们来明确什么时候使用它们。它们看起来可能相似,但用途不同,功能也各有特点。

特性 接口 抽象类
方法 只有方法签名 抽象方法和具体方法都有
属性 只有常量 可以有属性
多重继承 一个类可以实现多个接口 一个类只能继承一个类
构造函数 可以声明 __construct 签名(没有函数体) 可以定义带函数体的构造函数

当你想定义一个可由无关类实现的契约时,可以使用接口。例如,Printer 和 Logger 都可以实现 Writable 接口,即使它们没有共同的祖先类。

当你有一些相关的类需要共享通用代码时,可以使用抽象类。如果你的 Dog 类和 Cat 类都需要相同的 eat() 方法实现,抽象 Animal 类可以让你只编写一次这段代码。

你也可以结合这两种方式。一个类可以继承抽象类,同时实现多个接口:

<?php
abstract class Animal {
    protected $name;
    
    public function eat() {
        return $this->name . " is eating";
    }
}

interface Swimmable {
    public function swim();
}

class Duck extends Animal implements Swimmable {
    public function __construct($name) {
        $this->name = $name;
    }
    
    public function swim() {
        return $this->name . " is swimming";
    }
}

关键要点:当你需要在互不相关的类之间定义功能时,选择接口。当你需要在相关类之间共享代码时,选择抽象类。

challenge icon

挑战

简单

让我们构建一个车辆系统,演示何时使用抽象类而不是接口,以及如何有效地结合这两种方式。

你将创建一个系统,让车辆通过继承共享通用属性,同时也能通过接口获得额外能力。这反映了现实世界中的设计决策:汽车“是一种”车辆(继承),但它也“具备”加油能力(接口)。

将代码分布在 4 个文件中:

  • Refuelable.php:定义一个 Refuelable 接口,其中包含一个方法签名:refuel($amount)。任何需要加油的类都可以具备这项能力,不受其继承层级的限制。
  • Vehicle.php:定义一个抽象 Vehicle 类,为所有车辆提供共享功能。它应有一个受保护的 $brand 属性和一个受保护的 $fuelLevel 属性(初始值为 0)。构造函数接收品牌名称。添加一个具体方法 getBrand(),用于返回品牌;添加一个具体方法 getFuelLevel(),用于返回当前油量;再添加一个抽象方法 drive(),供子类实现。
  • Car.php:创建一个继承 Vehicle 并实现 Refuelable 的 Car 类。在文件顶部引入这两个必需的文件。构造函数接收品牌,并将其传递给父类构造函数。实现 drive(),使其返回 "[brand] car is driving"。实现 refuel($amount),将加油量加到油量中,并返回 "[brand] refueled to [fuelLevel] liters"。
  • main.php:引入 Car 文件。你将收到两个输入:品牌名称和加油量(将其转换为整数)。使用该品牌创建一个 Car。在第一行打印 drive() 的结果,然后在第二行打印传入加油量的 refuel() 结果。

这个挑战说明了两者的关键区别:抽象 Vehicle 类共享代码并建立“一种”关系,而 Refuelable 接口则添加了一项能力,其他不相关的类(例如发电机或船)也可以具备这项能力,而不必是车辆。

亲手试试

<?php
require_once 'Car.php';

// 读取输入
$brand = trim(fgets(STDIN));
$fuelAmount = intval(trim(fgets(STDIN)));

// TODO:用品牌创建一个 Car 对象

// TODO:在第一行打印 drive() 的结果

// TODO:在第二行打印传入燃油量后 refuel() 的结果
?>
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: PHP 在线编译器