枚举类需放在 app/Enums/ 目录、命名空间为 App\Enums,运行 composer dump-autoload -o 后用 class_exists() 验证;迁移中 enum() 字段须传 name 数组,$casts 键名须与字段名完全一致,推荐用 castUsing() 自定义 Cast 处理旧数据。

检查枚举类是否被正确自动加载
“Class not found” 是最常见拦路虎,不是代码写错,而是 Composer 根本没找到你的枚举类。Laravel 默认只扫描 app/ 目录下符合 PSR-4 的命名空间(如 App\Enums),如果你把枚举放在 enums/ 或 src/Enums/ 这类非标准路径,composer dump-autoload 也救不了它。
- 确认枚举文件路径为
app/Enums/UserType.php(注意大小写和目录层级) - 检查命名空间是否为
namespace App\Enums;,不是namespace Enums;或空命名空间 - 运行
composer dump-autoload -o强制刷新自动加载映射 - 在 Tinker 中执行
class_exists(\App\Enums\UserType::class)验证是否能解析成功
验证迁移中 enum() 字段定义是否匹配枚举值
Blueprint::enum() 不接受 PHP 枚举的 cases() 方法返回值,它只要一个纯字符串数组。如果直接传 UserType::cases(),迁移会报错或生成空 ENUM 列表,导致后续类型转换失效。
- 必须显式提取每个 case 的
name:array_map(fn($case) => $case->name, UserType::cases()) - 确保枚举是标量枚举(
enum UserType: string),否则$case->name不存在 - 检查数据库字段实际值是否全在枚举定义范围内——比如数据库里存了
'admin',但枚举里只有case Admin = 'administrator',就会触发转换失败
排查 $casts 配置与数据库字段的三重对齐问题
$casts 看似简单,但失效往往卡在三个“必须一致”上:字段名、数据库类型、PHP 类型。哪怕字段名多一个下划线,它就静默跳过,不报错也不转换。
- 模型中
$casts = ['type' => UserType::class]的键type必须和数据库字段名**完全一致**(包括大小写、下划线) - 数据库字段类型要是
VARCHAR或ENUM,不能是TEXT或INT;如果是ENUM('user','admin'),值必须严格匹配枚举name - 用
var_export($model->type)检查真实值类型,别信dd()的美化输出——如果返回的是字符串而非枚举实例,说明$casts根本没生效
确认是否用了 castUsing() 替代 $casts 字符串引用
Laravel 9+ 推荐用 castUsing() 显式声明自定义 Cast 类,而不是在 $casts 里写类名字符串。后者在 IDE 跳转、单元测试、错误堆栈里都难追踪,且一旦类加载失败,框架只会静默 fallback 到字符串。
- 在模型中改用:
protected function casts(): array { return ['type' => UserTypeCast::class]; } - 确保
UserTypeCast实现了CastsAttributes接口,并在get()中处理无效值(比如数据库有遗留'bot',而新枚举已移除该 case) - 别漏掉
set()方法——否则保存时会把整个枚举对象塞进数据库,而不是它的value
最常被忽略的是:枚举值变更后,旧数据不会自动迁移。即使你加了新 case 或删了旧 case,数据库里那些“幽灵值”仍存在,而默认 Cast 会直接抛异常。这时候不靠自定义 Cast 做兜底,系统随时可能崩在某个详情页上。


















