PHP 怎么用枚举改善

wen PHP项目 1

本文目录导读:

PHP 怎么用枚举改善

  1. 基础枚举定义
  2. 改善魔术数字和字符串
  3. 带方法的枚举
  4. 状态模式改善
  5. 配置与常量定义
  6. 数据库字段验证
  7. 业务规则封装
  8. 表单状态处理
  9. 表单状态处理
  10. 最佳实践总结
  11. 主要优势

在 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

主要优势

  1. 类型安全:编译器会检查类型
  2. 代码清晰:自文档化的代码
  3. 减少错误:避免拼写错误和无效值
  4. 易于维护:集中管理相关的常量
  5. IDE支持:自动补全和类型提示
  6. 模式匹配:与 match 表达式完美配合

使用枚举能显著提高代码质量和可维护性,特别适合处理状态机、配置选项和业务规则等场景。

抱歉,评论功能暂时关闭!