Menu
CoddyTech

抽象类

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

抽象类是不能直接实例化的类。它为其他类提供蓝图,并定义子类必须实现的方法。你可以使用 abstract 关键字创建抽象类。

<?php
abstract class Shape {
    protected $color;
    
    public function __construct($color) {
        $this->color = $color;
    }
    
    abstract public function calculateArea();
    
    public function getColor() {
        return $this->color;
    }
}

class Rectangle extends Shape {
    private $width;
    private $height;
    
    public function __construct($color, $width, $height) {
        parent::__construct($color);
        $this->width = $width;
        $this->height = $height;
    }
    
    public function calculateArea() {
        return $this->width * $this->height;
    }
}

$rect = new Rectangle("blue", 5, 3);
echo $rect->calculateArea();

输出:

15

Shape 类声明了抽象方法 calculateArea(),但没有提供实现。任何继承 Shape 的类都必须实现这个方法。注意,抽象类也可以包含普通方法,例如 getColor(),子类可以直接继承这些方法。

抽象方法定义了子类必须做什么,但不定义如何做。这样可以确保所有形状都有 calculateArea() 方法,同时允许每种形状用不同的方式计算面积。

要点:抽象类将继承结构与强制要求结合起来。当你想在相关类之间共享代码,同时确保每个子类都实现某些方法时,可以使用抽象类。

challenge icon

挑战

简单

我们来构建一个媒体播放器系统,展示抽象类如何规定契约,同时允许不同的媒体类型实现各自的播放行为。

你将把代码分到三个文件中:

  • Media.php:定义一个抽象 Media 类,作为所有媒体类型的蓝图。它应包含一个受保护的 $title 属性,以及一个用于接收并设置标题的构造函数。添加一个名为 play() 的抽象方法,子类必须实现它。再添加一个常规方法 getTitle(),用于返回标题。所有子类都会继承这个具体方法。
  • Song.php:定义一个继承 Media 的 Song 类。在文件顶部引入 Media 文件。这个类会添加一个 $artist 属性。构造函数应接收标题和艺术家:使用 parent::__construct() 设置标题,然后自行设置艺术家。实现必需的 play() 方法,使其返回 "Playing song: [title] by [artist]"。
  • Podcast.php:定义一个继承 Media 的 Podcast 类。在文件顶部引入 Media 文件。这个类会添加一个 $episode 属性(整数)。构造函数应接收标题和集数:使用 parent::__construct() 设置标题,然后设置集数。实现必需的 play() 方法,使其返回 "Playing podcast: [title] - Episode [episode]"。

在 main.php 中,引入 Song 和 Podcast 文件。你会收到 4 个输入:歌曲标题、艺术家姓名、播客标题和集数(输入为字符串,需要转换为整数)。使用这些值创建一个 Song 对象和一个 Podcast 对象。先打印对歌曲调用 play() 的结果,再打印对播客调用 play() 的结果,每个结果各占一行。

这个挑战展示了抽象类如何定义契约:每种媒体类型都必须有一个 play() 方法,但每种类型的实现方式都不同。抽象 Media 类不能直接实例化,它的作用只是为子类提供结构和共享功能。

亲手试试

<?php
require_once 'Song.php';
require_once 'Podcast.php';

// 读取输入
$songTitle = trim(fgets(STDIN));
$artistName = trim(fgets(STDIN));
$podcastTitle = trim(fgets(STDIN));
$episodeNumber = intval(trim(fgets(STDIN)));

// TODO: 使用 songTitle 和 artistName 创建一个 Song 对象

// TODO: 使用 podcastTitle 和 episodeNumber 创建一个 Podcast 对象

// TODO: 输出对歌曲调用 play() 的结果

// TODO: 输出对播客调用 play() 的结果

?>
quiz icon自我测试

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

面向对象编程中的所有课

自己练习: PHP 在线编译器