枚举基础概念
PHP 8.1 引入了枚举(Enum)功能,枚举是一种特殊的数据类型,它允许你定义一组命名的常量,使用枚举可以提高代码的可读性和类型安全性,
PHP 的枚举肉眼可见的参考了 Rust 的语法
php
<?php
// 定义一个简单的单位枚举
enum Status {
case PENDING;
case APPROVED;
case REJECTED;
}
// 使用枚举
$orderStatus = Status::PENDING;
echo $orderStatus->name; // 输出: PENDING
// 检查枚举值
if ($orderStatus === Status::PENDING) {
echo "订单待处理";
}
// 遍历所有枚举值
foreach (Status::cases() as $status) {
echo $status->name . "\n";
}
// 输出:
// PENDING
// APPROVED
// REJECTED标量枚举(带值的枚举)
标量枚举允许你为每个枚举值分配一个标量值(字符串或整数),
php
<?php
// 字符串值枚举
enum Color: string {
case RED = '#FF0000';
case GREEN = '#00FF00';
case BLUE = '#0000FF';
}
// 整数值枚举
enum Priority: int {
case LOW = 1;
case MEDIUM = 2;
case HIGH = 3;
case CRITICAL = 4;
}
// 使用标量枚举
$favoriteColor = Color::RED;
echo $favoriteColor->value; // 输出: #FF0000
echo $favoriteColor->name; // 输出: RED
$taskPriority = Priority::HIGH;
echo $taskPriority->value; // 输出: 3
// 从值创建枚举实例
$colorFromValue = Color::from('#00FF00');
echo $colorFromValue->name; // 输出: GREEN
// 安全的值转换(如果值不存在会返回null)
$maybeColor = Color::tryFrom('#FFFFFF');
var_dump($maybeColor); // 输出: null
// 检查枚举值是否存在
try {
$invalidColor = Color::from('#XXXXXX'); // 会抛出 ValueError
} catch (ValueError $e) {
echo "无效的颜色值\n";
}单位枚举(不带值的枚举)
单位枚举是不带值的枚举,每个枚举值都是唯一的实例,
php
<?php
enum Direction {
case NORTH;
case SOUTH;
case EAST;
case WEST;
// 可以为单位枚举添加方法
public function getOpposite(): self {
return match($this) {
self::NORTH => self::SOUTH,
self::SOUTH => self::NORTH,
self::EAST => self::WEST,
self::WEST => self::EAST,
};
}
public function getDescription(): string {
return match($this) {
self::NORTH => '北方',
self::SOUTH => '南方',
self::EAST => '东方',
self::WEST => '西方',
};
}
}
// 使用单位枚举
$facing = Direction::NORTH;
echo $facing->getDescription(); // 输出: 北方
$opposite = $facing->getOpposite();
echo $opposite->name; // 输出: SOUTH
echo $opposite->getDescription(); // 输出: 南方枚举方法
枚举可以定义自己的方法,包括静态方法和实例方法,
php
<?php
enum UserRole: string {
case ADMIN = 'admin';
case MODERATOR = 'moderator';
case USER = 'user';
case GUEST = 'guest';
// 实例方法
public function canEdit(): bool {
return in_array($this, [self::ADMIN, self::MODERATOR]);
}
public function canDelete(): bool {
return $this === self::ADMIN;
}
public function getLevel(): int {
return match($this) {
self::ADMIN => 4,
self::MODERATOR => 3,
self::USER => 2,
self::GUEST => 1,
};
}
// 静态方法
public static function getEditableRoles(): array {
return array_filter(self::cases(), function($role) {
return $role->canEdit();
});
}
public function getColor(): string {
return match($this) {
self::ADMIN => 'red',
self::MODERATOR => 'blue',
self::USER => 'green',
self::GUEST => 'gray',
};
}
}
// 使用枚举方法
$userRole = UserRole::MODERATOR;
var_dump($userRole->canEdit()); // bool(true)
var_dump($userRole->canDelete()); // bool(false)
echo $userRole->getLevel(); // 3
// 获取所有可编辑角色
$editableRoles = UserRole::getEditableRoles();
foreach ($editableRoles as $role) {
echo $role->name . "\n"; // ADMIN 和 MODERATOR
}枚举与接口
枚举可以实现接口,这使得枚举可以遵循特定的行为规范,
php
<?php
// 定义接口
interface PermissionInterface {
public function hasPermission(string $action): bool;
public function getDisplayName(): string;
}
// 枚举实现接口
enum AccountType: string implements PermissionInterface {
case FREE = 'free';
case PREMIUM = 'premium';
case ENTERPRISE = 'enterprise';
public function hasPermission(string $action): bool {
return match($this) {
self::FREE => in_array($action, ['read', 'comment']),
self::PREMIUM => in_array($action, ['read', 'comment', 'upload']),
self::ENTERPRISE => true, // 所有权限
};
}
public function getDisplayName(): string {
return match($this) {
self::FREE => '免费账户',
self::PREMIUM => '高级账户',
self::ENTERPRISE => '企业账户',
};
}
// 额外的枚举特定方法
public function getStorageLimit(): int {
return match($this) {
self::FREE => 100, // MB
self::PREMIUM => 1000, // MB
self::ENTERPRISE => PHP_INT_MAX, // 无限制
};
}
}
// 使用实现接口的枚举
$account = AccountType::PREMIUM;
echo $account->getDisplayName(); // 高级账户
var_dump($account->hasPermission('upload')); // bool(true)
var_dump($account->hasPermission('admin_panel')); // bool(false)
echo $account->getStorageLimit(); // 1000枚举的类型安全
枚举提供了严格的类型安全,确保变量只能是预定义的枚举值之一,
php
<?php
enum PaymentStatus: string {
case PENDING = 'pending';
case COMPLETED = 'completed';
case FAILED = 'failed';
case REFUNDED = 'refunded';
}
class PaymentProcessor {
private PaymentStatus $status;
public function __construct(PaymentStatus $initialStatus = PaymentStatus::PENDING) {
$this->status = $initialStatus;
}
public function process(): void {
if ($this->status !== PaymentStatus::PENDING) {
throw new LogicException('只能处理待处理的支付');
}
// 模拟支付处理
$this->status = PaymentStatus::COMPLETED;
}
public function refund(): void {
if ($this->status !== PaymentStatus::COMPLETED) {
throw new LogicException('只能退款已完成的支付');
}
$this->status = PaymentStatus::REFUNDED;
}
public function getStatus(): PaymentStatus {
return $this->status;
}
public function getStatusName(): string {
return match($this->status) {
PaymentStatus::PENDING => '待处理',
PaymentStatus::COMPLETED => '已完成',
PaymentStatus::FAILED => '失败',
PaymentStatus::REFUNDED => '已退款',
};
}
}
// 使用示例
$payment = new PaymentProcessor();
echo $payment->getStatusName(); // 待处理
$payment->process();
echo $payment->getStatusName(); // 已完成
$payment->refund();
echo $payment->getStatusName(); // 已退款
// 类型安全示例 - 以下代码会报错,因为参数必须是PaymentStatus枚举值
// $invalidPayment = new PaymentProcessor('invalid_status'); // 这在运行时会报错枚举的实际应用示例
以下是一个完整的实际应用示例,展示枚举在真实项目中的使用:
php
<?php
// HTTP状态码枚举
enum HttpStatusCode: int {
case OK = 200;
case CREATED = 201;
case BAD_REQUEST = 400;
case UNAUTHORIZED = 401;
case FORBIDDEN = 403;
case NOT_FOUND = 404;
case INTERNAL_SERVER_ERROR = 500;
public function getReasonPhrase(): string {
return match($this) {
self::OK => 'OK',
self::CREATED => 'Created',
self::BAD_REQUEST => 'Bad Request',
self::UNAUTHORIZED => 'Unauthorized',
self::FORBIDDEN => 'Forbidden',
self::NOT_FOUND => 'Not Found',
self::INTERNAL_SERVER_ERROR => 'Internal Server Error',
};
}
public function isSuccessful(): bool {
return $this->value >= 200 && $this->value < 300;
}
public function isClientError(): bool {
return $this->value >= 400 && $this->value < 500;
}
public function isServerError(): bool {
return $this->value >= 500 && $this->value < 600;
}
}
// API响应类
class ApiResponse {
public function __construct(
private readonly mixed $data,
private readonly HttpStatusCode $status = HttpStatusCode::OK,
private readonly array $headers = []
) {}
public function send(): void {
http_response_code($this->status->value);
foreach ($this->headers as $name => $value) {
header("$name: $value");
}
header('Content-Type: application/json');
echo json_encode([
'status' => $this->status->value,
'message' => $this->status->getReasonPhrase(),
'data' => $this->data
]);
}
public static function success(mixed $data, HttpStatusCode $status = HttpStatusCode::OK): self {
return new self($data, $status);
}
public static function error(string $message, HttpStatusCode $status = HttpStatusCode::INTERNAL_SERVER_ERROR): self {
return new self(['error' => $message], $status);
}
}
// 使用示例
try {
// 模拟API请求处理
$userData = ['id' => 1, 'name' => '张三', 'email' => 'zhangsan@example.com'];
$response = ApiResponse::success($userData, HttpStatusCode::OK);
$response->send();
} catch (Exception $e) {
$errorResponse = ApiResponse::error($e->getMessage(), HttpStatusCode::INTERNAL_SERVER_ERROR);
$errorResponse->send();
}
// 枚举验证示例
function validateStatus(HttpStatusCode $status): string {
if ($status->isSuccessful()) {
return "成功状态码: {$status->value}";
} elseif ($status->isClientError()) {
return "客户端错误: {$status->value}";
} elseif ($status->isServerError()) {
return "服务器错误: {$status->value}";
}
return "其他状态码: {$status->value}";
}
echo validateStatus(HttpStatusCode::NOT_FOUND); // 客户端错误: 404
echo validateStatus(HttpStatusCode::INTERNAL_SERVER_ERROR); // 服务器错误: 500PHP枚举提供了一种类型安全的方式来处理预定义的值集合,相比传统的常量定义, 枚举提供了更好的代码组织和类型检查,枚举特别适用于状态、类型、选项等场景, 能够显著提高代码的可读性和维护性,