Menu
CoddyTech

枚举(PHP 8.1)

本课属于 Coddy PHP 学习旅程的“面向对象编程”单元。第 59 课,共 91 课。

在 PHP 8.1 之前,要表示状态或类型这类固定的一组值,意味着需要使用类常量或魔法字符串,这两种方式都容易出错。枚举提供了一种合适的方式来定义一种只能包含特定预定义值的类型。

使用 enum 关键字定义枚举:

<?php
enum Status {
    case Pending;
    case Active;
    case Completed;
}

$status = Status::Active;
echo $status->name;

输出:

Active

枚举也可以有关联值,也就是与每个枚举项关联的字符串或整数值。在数据库或 API 中存储枚举时,这很有用:

<?php
enum Status: string {
    case Pending = 'pending';
    case Active = 'active';
    case Completed = 'completed';
}

$status = Status::Active;
echo $status->value;

输出:

active

带值枚举提供了 from() 方法,可根据值创建枚举;还提供了 tryFrom(),对于无效值,它会返回 null,而不是抛出错误:

<?php
$status = Status::from('active');      // 返回 Status::Active
$invalid = Status::tryFrom('unknown'); // 返回 null

枚举还可以包含方法,因此能够强大地封装相关逻辑。它们与类型提示配合得很好,确保你的函数只接受有效值,不必再检查字符串是否与预期选项匹配。

challenge icon

挑战

简单

让我们构建一个订单管理系统,用枚举以类型安全的方式表示订单状态。你不再依赖可能拼写错误或无效的字符串,而是创建一个后备枚举,将每种状态映射到适合数据库使用的值。

你将把代码分到三个文件中:

  • OrderStatus.php:创建一个名为 OrderStatus 的字符串后备枚举,包含四种情况:
    • Pending 对应 'pending'
    • Processing 对应 'processing'
    • Shipped 对应 'shipped'
    • Delivered 对应 'delivered'
    添加一个 label() 方法,为每种状态返回易于理解的描述:
    • Pending 返回 "Awaiting confirmation"
    • Processing 返回 "Being prepared"
    • Shipped 返回 "On the way"
    • Delivered 返回 "Order complete"
  • Order.php:创建一个使用该枚举的 Order 类。引入 OrderStatus 文件。该类应当:
    • 使用构造函数属性提升,在构造函数中接收订单 ID(字符串)和一个 OrderStatus
    • 包含一个 getInfo() 方法,返回 "Order [id]: [status label]"
    • 包含一个 getStatusValue() 方法,返回状态的后备值(可用于存储到数据库)
  • main.php:引入 Order 文件。你会收到两个输入:订单 ID 和状态字符串(例如 "shipped")。使用 tryFrom() 将字符串输入安全地转换为 OrderStatus 枚举。如果状态有效,就创建一个 Order 并打印两行:
    • getInfo() 的结果
    • getStatusValue() 的结果
    如果状态字符串无效,就打印 "Invalid status"。

这个挑战展示了枚举如何提供类型安全。你的 Order 类只能接受有效状态,而 tryFrom() 方法能让你安全地处理用户输入,避免无效值带来的风险。

亲手试试

<?php

require_once 'Order.php';

// 读取输入
$orderId = trim(fgets(STDIN));
$statusString = trim(fgets(STDIN));

// TODO:使用 OrderStatus::tryFrom() 安全地将状态字符串转换为枚举
// 如果值无效,tryFrom() 会返回 null

// TODO:如果状态有效,创建一个 Order 并打印:
// getInfo() 的结果
// getStatusValue() 的结果

// TODO:如果状态无效,打印 "Invalid status"

?>
quiz icon自我测试

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

面向对象编程中的所有课

自己练习: PHP 在线编译器