Menu
CoddyTech

使用多个特征

本课属于 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:00

Post 类现在拥有两个 trait 中的方法。每个 trait 都提供各自的功能:Timestampable 提供与时间相关的方法,而 Identifiable 负责处理唯一 ID。这种做法让每个 trait 专注于单一职责,使你的代码更模块化,也更容易复用。

当两个 trait 有同名方法时会发生什么?这是一个冲突情况,我们将在下一课中探讨。

challenge icon

挑战

简单

让我们构建一个产品管理系统,通过组合多个 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 和 Stockable trait 的 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"
?>
quiz icon自我测试

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

面向对象编程中的所有课

自己练习: PHP 在线编译器