Laravel 用 Enum 与 Casts 把状态字段变成类型安全枚举,告别魔法字符串

test12026-10-093 次阅读

魔法字符串的代价

订单状态、审核结果这类字段,常见写法是表里存字符串,业务里到处比较 $order->status === 'pending'。拼写错一个字母就悄悄走了错误分支,IDE 也帮不上忙。PHP 8.1 的枚举配合 Laravel 的 Casts 能把字段变成真正的类型,赋值和判断都受编译期与运行期双重约束。

定义 backed enum

用 string backed enum 把合法取值固定下来,每个 case 对应数据库里存的值。

namespace App\Enums;

enum OrderStatus: string
{
    case Pending = 'pending';
    case Paid = 'paid';
    case Shipped = 'shipped';
    case Done = 'done';
    case Cancelled = 'cancelled';
}

用 Cast 绑定模型字段

在模型里用 $casts 把 status 字段映射到枚举,读写时 Laravel 自动转换,拿到的是 OrderStatus 实例而非裸字符串。

namespace App\Models;

use App\Enums\OrderStatus;
use Illuminate\Database\Eloquent\Model;

class Order extends Model
{
    protected $casts = [
        'status' => OrderStatus::class,
    ];
}

类型安全地赋值与判断

赋值只能传枚举 case,比较用身份运算符,拼错 case 直接编译报错;还能给枚举加方法封装状态流转规则。

$order = Order::find(1);

// 赋值:只能是枚举,传字符串会抛异常
$order->status = OrderStatus::Paid;
$order->save();

// 判断:用身份比较,安全清晰
if ($order->status === OrderStatus::Paid) {
    // 已支付分支
}

// 查询:直接传枚举,底层自动转成存储值
Order::where('status', OrderStatus::Shipped)->count();

实践建议

  • 枚举适合"有限且稳定"的取值集;状态还会频繁新增时,谨慎评估是否值得上枚举。
  • 给枚举加方法能收口流转逻辑,例如 canTransitionTo(OrderStatus $next) 统一把关。
  • 数据库迁移里把字段设成与 enum 对应的值类型(如 varchar 或 tinyint),避免存储歧义。
  • 旧项目改造可平滑过渡:先加 enum 与 cast,再逐步替换散落的字符串比较。
T

test1

文章作者

魔法字符串的代价 订单状态、审核结果这类字段,常见写法是表里存字符串,业务里到处比较 $order->status =...

分类
技术
发布时间
2026-10-09
字数
约 1240 字
阅读
3 次