解决特征冲突
本课属于 Coddy PHP 学习旅程的“面向对象编程”单元。第 53 课,共 91 课。
当两个 trait 定义了同名的方法时,PHP 会抛出致命错误。你必须使用 insteadof 和 as 运算符,明确告诉 PHP 如何处理这个冲突。
<?php
trait FileLogger {
public function log(string $message): void {
echo "File: $message";
}
}
trait DatabaseLogger {
public function log(string $message): void {
echo "DB: $message";
}
}
class Application {
use FileLogger, DatabaseLogger {
FileLogger::log insteadof DatabaseLogger;
DatabaseLogger::log as logToDatabase;
}
}
$app = new Application();
$app->log("Error occurred");
$app->logToDatabase("Error occurred");
输出:
File: Error occurred
DB: Error occurred发生冲突时,insteadof 运算符会选择使用哪个 trait 的方法。在这个示例中,FileLogger::log 优先,因此会成为默认的 log() 方法。as 运算符会创建别名,让你可以用另一个名称访问另一个 trait 的方法。
你也可以使用 as 来更改方法的可见性:
<?php
trait Greeting {
public function sayHello(): void {
echo "Hello!";
}
}
class Person {
use Greeting {
sayHello as private;
}
}
这样一来,sayHello() 在 Person 类中就是私有的,尽管它在 trait 中是公开的。冲突解决让你可以精细地控制 trait 方法如何集成到类中。
挑战
简单我们来构建一个通知系统,让不同的渠道都能发送消息,但当多个 trait 提供了同名方法时,我们需要解决冲突。
你需要将代码组织在 4 个文件中:
EmailNotifier.php:创建一个名为EmailNotifier的 trait,其中包含方法notify(string $message),该方法返回"Email: [message]"。SmsNotifier.php:创建一个名为SmsNotifier的 trait,其中包含方法notify(string $message),该方法返回"SMS: [message]"。AlertService.php:创建一个同时使用这两个 trait 的AlertService类。由于两个 trait 都有notify()方法,你需要解决这个冲突:- 使用
EmailNotifier::notify作为默认的notify()方法 - 为
SmsNotifier::notify方法创建别名notifyBySms
notifyAll(string $message),调用这两个通知方法,并将它们的结果合并到不同的行中返回。- 使用
main.php:引入所有必需的文件,并创建一个AlertService实例。你会收到一个输入:消息字符串。输出 3 行:- 使用该消息调用
notify()的结果 - 使用该消息调用
notifyBySms()的结果 - 使用该消息调用
notifyAll()的结果
- 使用该消息调用
这展示了当方法名称冲突时,insteadof 如何决定使用哪个 trait 的方法,而 as 则可以让你用另一个名称继续访问另一个 trait 的方法。
亲手试试
<?php
require_once 'AlertService.php';
// 读取输入
$message = trim(fgets(STDIN));
// TODO:创建一个 AlertService 实例
// TODO:传入消息调用 notify(),并打印结果
// TODO:传入消息调用 notifyBySms(),并打印结果
// TODO:传入消息调用 notifyAll(),并打印结果
?>这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: PHP 在线编译器