本文目录导读:

在 PHP 中,枚举(Enum)是 PHP 8.1 引入的重要特性,以下是使用枚举改善代码质量的各种方式:
基础枚举定义
<?php
// 纯枚举(只有值)
enum UserStatus
{
case Active;
case Inactive;
case Banned;
case Pending;
}
// 带后端值的枚举
enum OrderStatus: string
{
case Pending = 'pending';
case Paid = 'paid';
case Shipped = 'shipped';
case Delivered = 'delivered';
case Cancelled = 'cancelled';
}
改善魔术数字和字符串
<?php
// ❌ 不好的做法
class UserController
{
public function updateStatus(int $status)
{
// 1,2,3 是什么?难以理解
if ($status === 1) {
// do something
} elseif ($status === 2) {
// do something else
}
}
}
// ✅ 使用枚举改善
class UserController
{
public function updateStatus(UserStatus $status)
{
match($status) {
UserStatus::Active => $this->activateUser(),
UserStatus::Inactive => $this->deactivateUser(),
UserStatus::Banned => $this->banUser(),
UserStatus::Pending => $this->pendingUser(),
};
}
}
带方法的枚举
<?php
enum PaymentMethod: string
{
case CreditCard = 'credit_card';
case PayPal = 'paypal';
case BankTransfer = 'bank_transfer';
// 添加方法
public function getDescription(): string
{
return match($this) {
self::CreditCard => '使用信用卡支付',
self::PayPal => '使用PayPal支付',
self::BankTransfer => '使用银行转账',
};
}
// 检查是否支持特定功能
public function isOnline(): bool
{
return match($this) {
self::CreditCard, self::PayPal => true,
self::BankTransfer => false,
};
}
// 添加静态方法
public static function getOnlineMethods(): array
{
return array_filter(
self::cases(),
fn($method) => $method->isOnline()
);
}
}
状态模式改善
<?php
enum OrderState
{
case Pending;
case Processing;
case Shipped;
case Delivered;
// 状态转换规则
public function canTransitionTo(self $nextState): bool
{
return match($this) {
self::Pending => in_array($nextState, [self::Processing, self::Cancelled]),
self::Processing => in_array($nextState, [self::Shipped, self::Cancelled]),
self::Shipped => in_array($nextState, [self::Delivered, self::Cancelled]),
self::Delivered => false, // 终态
};
}
// 转换方法
public function transitionTo(self $nextState): self
{
if (!$this->canTransitionTo($nextState)) {
throw new InvalidArgumentException(
"不能从 {$this->name} 转换到 {$nextState->name}"
);
}
return $nextState;
}
}
配置与常量定义
<?php
enum AppEnv: string
{
case Development = 'dev';
case Testing = 'test';
case Staging = 'staging';
case Production = 'prod';
public function isProduction(): bool
{
return $this === self::Production;
}
public function getConfig(): array
{
return [
'debug' => !$this->isProduction(),
'cache' => $this->isProduction(),
'log_level' => $this->isProduction() ? 'error' : 'debug',
];
}
}
// 使用
$env = AppEnv::from($_ENV['APP_ENV']);
if (!$env->isProduction()) {
// 开发环境特殊处理
}
数据库字段验证
<?php
// 定义数据库字段的枚举
enum UserRole: string
{
case Admin = 'admin';
case Editor = 'editor';
case Subscriber = 'subscriber';
public function getPermissions(): array
{
return match($this) {
self::Admin => ['*'],
self::Editor => ['create', 'edit', 'delete'],
self::Subscriber => ['read'],
};
}
// 用于验证输入
public static function isValid(string $value): bool
{
return in_array($value, array_column(self::cases(), 'value'));
}
}
// 验证用户输入
$role = UserRole::tryFrom($_POST['role']);
if (!$role) {
throw new InvalidArgumentException('无效的用户角色');
}
业务规则封装
<?php
enum DiscountType
{
case Percentage;
case FixedAmount;
case FreeShipping;
public function calculateDiscount(float $subtotal, float $value): float
{
return match($this) {
self::Percentage => $subtotal * ($value / 100),
self::FixedAmount => min($value, $subtotal),
self::FreeShipping => 0, // 运费折扣单独计算
};
}
public function getValidationRule(): array
{
return match($this) {
self::Percentage => ['min' => 1, 'max' => 100],
self::FixedAmount => ['min' => 0.01, 'max' => PHP_INT_MAX],
self::FreeShipping => ['min' => 0, 'max' => 0],
};
}
}
表单状态处理
<?php
enum CacheDriver: string
{
case File = 'file';
case Redis = 'redis';
case Memcached = 'memcached';
case Database = 'database';
public function getConfig(): array
{
return match($this) {
self::File => ['path' => storage_path('cache')],
self::Redis => ['host' => env('REDIS_HOST'), 'port' => 6379],
self::Memcached => ['host' => env('MEMCACHED_HOST'), 'port' => 11211],
self::Database => ['table' => 'cache'],
};
}
public static function getDefault(): self
{
return self::File;
}
}
表单状态处理
<?php
// 表单验证状态
enum FormValidationState
{
case Valid;
case Invalid;
case Pending;
public function getLabel(): string
{
return match($this) {
self::Valid => '✓ 验证通过',
self::Invalid => '✗ 验证失败',
self::Pending => '⏳ 等待验证',
};
}
public function getCssClass(): string
{
return match($this) {
self::Valid => 'success',
self::Invalid => 'error',
self::Pending => 'pending',
};
}
}
最佳实践总结
<?php
// 1. 使用枚举代替魔法值和魔字符串
// 2. 在方法参数中类型限制
// 3. 结合 match 表达式使用
// 4. 添加行为方法
// 5. 支持静态工厂方法
enum FilePermission
{
case Read;
case Write;
case Execute;
public function toOctal(): int
{
return match($this) {
self::Read => 4,
self::Write => 2,
self::Execute => 1,
};
}
public static function fromOctal(int $value): array
{
$permissions = [];
foreach (self::cases() as $permission) {
if ($value & $permission->toOctal()) {
$permissions[] = $permission;
}
}
return $permissions;
}
}
// 使用示例
$permissions = [FilePermission::Read, FilePermission::Write];
$octal = array_reduce($permissions,
fn($carry, $perm) => $carry | $perm->toOctal(), 0);
// $octal = 6
主要优势
- 类型安全:编译器会检查类型
- 代码清晰:自文档化的代码
- 减少错误:避免拼写错误和无效值
- 易于维护:集中管理相关的常量
- IDE支持:自动补全和类型提示
- 模式匹配:与 match 表达式完美配合
使用枚举能显著提高代码质量和可维护性,特别适合处理状态机、配置选项和业务规则等场景。