特征简介
本课属于 Coddy PHP 学习旅程的“面向对象编程”单元。第 51 课,共 91 课。
PHP 只支持单继承,也就是说,一个类只能扩展一个父类。但如果你需要在多个无关的类之间共享功能,该怎么办?这时就可以使用trait。
trait 是一种代码复用机制,你可以用它定义方法和属性,并将它们插入多个类中。你可以把 trait 看作语言层面的复制粘贴,也就是说,trait 中的代码会成为使用它的类的一部分。
<?php
trait Timestampable {
private string $createdAt;
public function setCreatedAt(): void {
$this->createdAt = date('Y-m-d H:i:s');
}
public function getCreatedAt(): string {
return $this->createdAt;
}
}
class Article {
use Timestampable;
public function __construct(public string $title) {
$this->setCreatedAt();
}
}
$article = new Article("PHP Traits");
echo $article->getCreatedAt();
类中的 use 关键字会导入 trait 的成员。现在,Article 可以使用 setCreatedAt() 和 getCreatedAt(),就像它们直接定义在类中一样。
同一个 trait 可以用于完全不相关的类中,例如 Comment 类、User 类,或任何需要时间戳功能的其他类。这样就解决了单继承的限制,让你可以在类层次结构中横向共享代码。
挑战
简单让我们构建一个简单的问候系统,展示 trait 如何让你在互不相关的类之间共享功能。你将创建一个提供问候功能的 trait,然后在两个完全不同的类中使用它。
你将把代码分到三个文件中:
Greetable.php:创建一个名为Greetable的 trait,用来提供问候功能。这个 trait 应包含:- 一个私有属性
$greeting(字符串) - 一个方法
setGreeting(string $greeting),用于保存问候消息 - 一个方法
greet(),用于返回问候消息
- 一个私有属性
Person.php:创建一个使用Greetabletrait 的Person类。引入 trait 文件,并使用构造函数属性提升来定义一个公开的$name属性。在构造函数中,调用setGreeting(),将问候语设置为"Hello, I'm [name]"。Robot.php:创建一个同样使用Greetabletrait 的Robot类。引入 trait 文件,并使用构造函数属性提升来定义一个公开的$model属性。在构造函数中,调用setGreeting(),将问候语设置为"Beep boop, I am model [model]"。
在 main.php 中,引入这两个类文件。你会收到两个输入:一个人的姓名和一个机器人的型号。创建这两个类的实例,并将它们的问候语分别打印在单独的行上。
这展示了 trait 的强大之处:Person 和 Robot 是完全不相关的类,没有共同的父类,但它们都通过 trait 获得了相同的问候功能。每个类都以自己的方式定制了这项功能的用法。
亲手试试
<?php
require_once 'Person.php';
require_once 'Robot.php';
// 读取输入
$name = trim(fgets(STDIN));
$model = trim(fgets(STDIN));
// TODO:用给定的名字创建一个 Person 实例
// TODO:用给定的型号创建一个 Robot 实例
// TODO:打印 Person 的问候语
// TODO:打印 Robot 的问候语(另起一行)
?>这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: PHP 在线编译器