$casts 是 Eloquent 唯一能统一控制字段读写类型转换的机制,boolean 和 integer 这类内置 cast 看似简单,但错配数据库类型、漏写 protected、或混用 mutator 就会失效——而且失效时往往没报错,只在 dd() 或 API 输出里悄悄暴露。

直接说结论:$casts 是 Eloquent 唯一能统一控制字段读写类型转换的机制,boolean 和 integer 这类内置 cast 看似简单,但错配数据库类型、漏写 protected、或混用 mutator 就会失效——而且失效时往往没报错,只在 dd() 或 API 输出里悄悄暴露。
为什么 boolean 有时返回 "1" 而不是 true
根本原因不是 Laravel 逻辑错,而是数据库字段类型和 cast 不匹配:
- MySQL 的
TINYINT(1)字段存1,配合'is_active' => 'boolean'才能转成true;如果字段是VARCHAR存字符串"true",Eloquent 不识别,$user->is_active就是字符串"true" -
booleancast 底层用的是(bool)强转,所以数据库值为0/1最稳;若存"t"或"f",得自定义 cast 类 - 迁移里用
$table->boolean('is_active')没问题,但别手动改成$table->tinyInteger('is_active')后还指望booleancast 自动适配——它不查字段定义,只按你写的 cast 类型处理值
integer cast 为什么对 "123" 字符串也通过
因为 integer cast 的行为是 (int) $value,不是类型校验。它不拒绝字符串数字,只负责“尽力转”:
- 数据库字段是
VARCHAR存"42"→$casts = ['age' => 'integer']→$user->age是整数42 - 但如果字段存的是
"42.5"或"abc",cast 后分别是42和0,静默截断,不会报错 - 真正要拦截非法输入,得靠验证规则:比如
'age' => 'required|integer|between:0,150',而不是依赖 cast - 注意:MySQL 的
INT字段本身存"123"(字符串)也能被 cast 成整数,但这是数据库隐式转换,非 Laravel 行为
常见组合陷阱:$casts + mutator + API 输出
一旦在模型里同时用了 $casts 和访问器(accessor),类型就可能打架:
- 写了
protected $casts = ['is_admin' => 'boolean'],又加了public function getIsAdminAttribute($value) { return (bool) $value; }—— 多余且危险,因为 accessor 会在 cast 后再执行一次,$value已是布尔值,(bool) true还是true,但逻辑冗余易出错 -
toArray()和json_encode()只走$casts,不调 accessor;而dd($user->is_admin)会触发 accessor(如果存在),导致调试时看到的值和 API 返回不一致 - 字段是
JSON类型(MySQL 5.7+),但没配'meta' => 'json'—— 数据库存的是 JSON 字符串,PHP 层取出来仍是字符串,不是数组 -
protected忘写或写成public $casts→ 整个数组被忽略,$casts不生效,连 warning 都没有
最常被忽略的一点:cast 是单向管道,只管「从数据库值 → PHP 值」和「PHP 值 → 数据库可存值」,它不管前端传来的原始请求体类型。API 入参校验必须另做,不能指望 $casts 替你拦住 "123" 或 null。


















