使用多个特征
本课属于 Coddy PHP 学习旅程的“面向对象编程”单元。第 52 课,共 91 课。
单个 trait 很有用,但真正的强大之处在于将多个 trait 组合到一个类中。PHP 允许你按需引入任意数量的 trait,让你的类同时具备来自多个来源的功能。
要使用多个 trait,只需在 use 关键字后用逗号分隔列出它们:
<?php
trait Timestampable {
public function getTimestamp(): string {
return date('Y-m-d H:i:s');
}
}
trait Identifiable {
private string $id;
public function generateId(): void {
$this->id = uniqid('id_');
}
public function getId(): string {
return $this->id;
}
}
class Post {
use Timestampable, Identifiable;
public function __construct(public string $title) {
$this->generateId();
}
}
$post = new Post("Hello World");
echo $post->getId() . " - " . $post->getTimestamp();
输出:
id_6789abc123 - 2024-01-15 10:30:00Post 类现在拥有两个 trait 中的方法。每个 trait 都提供各自的功能:Timestampable 提供与时间相关的方法,而 Identifiable 负责处理唯一 ID。这种做法让每个 trait 专注于单一职责,使你的代码更模块化,也更容易复用。
当两个 trait 有同名方法时会发生什么?这是一个冲突情况,我们将在下一课中探讨。
挑战
简单让我们构建一个产品管理系统,通过组合多个 trait,为产品同时添加定价和库存管理功能。每个 trait 都负责一项任务,而你的产品类将同时获得这两者的功能。
你将把代码分成三个文件:
Priceable.php:创建一个名为Priceable的 trait,用于处理定价功能。这个 trait 应包含:- 一个私有属性
$price(浮点数) - 一个用于保存价格的方法
setPrice(float $price) - 一个用于返回价格的方法
getPrice() - 一个用于返回价格格式化结果的方法
getFormattedPrice(),格式为"$[price]",保留 2 位小数
- 一个私有属性
Stockable.php:创建一个名为Stockable的 trait,用于管理库存。这个 trait 应包含:- 一个私有属性
$stock(整数) - 一个用于保存库存数量的方法
setStock(int $quantity) - 一个用于返回当前库存的方法
getStock() - 一个方法
isInStock():如果库存大于 0,则返回true;否则返回false
- 一个私有属性
main.php:引入两个 trait 文件,并创建一个同时使用Priceable和Stockabletrait 的Product类。使用构造函数属性提升来定义一个公共$name属性。构造函数还应接收价格和库存数量,并使用 trait 的方法设置它们。你会收到三个输入:产品名称、价格和库存数量。使用这些值创建一个产品,并打印四行内容:
- 产品名称
- 格式化后的价格(使用
getFormattedPrice()) - 库存数量
- 如果有库存,则输出
"Available";如果没有,则输出"Out of stock"
这展示了多个 trait 如何协同工作。你的 Product 类从一个 trait 获得定价功能,从另一个 trait 获得库存管理功能。每项职责都清晰分开,同时组合起来构成一个功能齐全的产品。
亲手试试
<?php
require_once 'Priceable.php';
require_once 'Stockable.php';
// TODO:创建一个同时使用 Priceable 和 Stockable trait 的 Product 类
// 对 public $name 属性使用构造函数属性提升
// 构造函数应接收 name、price 和 stock,并使用 trait 方法设置 price 和 stock
class Product {
// TODO:在这里使用这些 trait
// TODO:实现构造函数,并对 $name 使用构造函数属性提升
// 再使用 trait 方法设置 price 和 stock
}
// 读取输入
$name = trim(fgets(STDIN));
$price = floatval(trim(fgets(STDIN)));
$stock = intval(trim(fgets(STDIN)));
// TODO:使用输入值创建一个 Product 实例
// TODO:输出产品名称
// TODO:使用 getFormattedPrice() 输出格式化后的价格
// TODO:输出库存数量
// TODO:如果有库存,输出 "Available";否则输出 "Out of stock"
?>这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: PHP 在线编译器