再次探讨方法重写
本课属于 Coddy PHP 学习旅程的“面向对象编程”单元。第 33 课,共 91 课。
你已经在继承这一章学习过方法重写。现在,我们来看看它与多态的联系。多态是面向对象编程中最强大的概念之一。
多态的意思是“多种形式”。在子类中重写方法时,你赋予了这个方法不同的形式,同时保留了相同的名称。通过父类类型来操作对象时,奇妙之处就发生了:
<?php
class Animal {
public function speak() {
return "Some sound";
}
}
class Dog extends Animal {
public function speak() {
return "Woof!";
}
}
class Cat extends Animal {
public function speak() {
return "Meow!";
}
}
function makeAnimalSpeak(Animal $animal) {
return $animal->speak();
}
echo makeAnimalSpeak(new Dog()) . "\n";
echo makeAnimalSpeak(new Cat());
输出:
Woof!
Meow!函数 makeAnimalSpeak() 接受任意 Animal。它不知道也不关心接收到的是 Dog 还是 Cat。PHP 会在运行时根据实际对象的类型,自动调用正确的重写方法。
这就是多态的实际应用。
这种方法能让你编写灵活的代码,在不知道具体类型的情况下处理一组相关对象。之后你可以添加新的动物类,函数会自动适配它们。
要点:方法重写通过允许不同的类对同一个方法调用作出不同的响应来实现多态,具体响应由运行时的实际对象类型决定。
挑战
简单让我们构建一个乐器系统,通过方法重写来展示多态。你将创建一个基类 Instrument 和两个子类,每个子类都会发出独特的声音,然后使用一个函数以多态的方式演奏任意乐器。
你将把代码分成 4 个文件:
Instrument.php:创建一个Instrument类,其中包含一个通过构造函数设置的受保护属性$name。添加一个play()方法,返回"[name] makes a sound"。这是子类将要重写的基础行为。Guitar.php:创建一个继承Instrument的Guitar类。引入父类文件。构造函数接收名称,并将其传递给父类构造函数。重写play()方法,使其返回"[name] strums a chord"。Drum.php:创建一个继承Instrument的Drum类。引入父类文件。构造函数接收名称,并将其传递给父类构造函数。重写play()方法,使其返回"[name] beats a rhythm"。main.php:引入Guitar和Drum文件。创建一个名为performWith的函数,该函数接收一个Instrument参数(带类型提示),并返回对它调用play()的结果。这个函数展示了多态。通过父类的类型提示,它可以处理任何类型的乐器。
你会收到两个输入:吉他的名称和鼓的名称。使用这些名称创建一个 Guitar 和一个 Drum。将它们分别传递给 performWith() 函数并打印结果:先打印吉他,再打印鼓,每个结果各占一行。
注意,performWith() 接收的是任意一个 Instrument,但 PHP 会在运行时根据实际对象类型自动调用正确的重写版 play() 方法。这就是多态的实际应用!
亲手试试
<?php
// 引入乐器文件
require_once 'Guitar.php';
require_once 'Drum.php';
// 读取输入
$guitarName = trim(fgets(STDIN));
$drumName = trim(fgets(STDIN));
// TODO:创建一个名为 performWith 的函数,要求:
// 接受一个 Instrument 参数(使用类型提示:Instrument $instrument)
// 返回对乐器调用 play() 的结果
// TODO:用 $guitarName 创建一个 Guitar,用 $drumName 创建一个 Drum
// TODO:分别将它们传给 performWith() 并打印结果(先吉他,后鼓)
?>这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: PHP 在线编译器