用 fillable,别碰 guarded。fillable 是白名单机制,仅允许显式列出的字段批量赋值,安全边界清晰;guarded 是黑名单机制,易因漏写字段导致未授权数据写入,Laravel 5.8 起已明确弃用。

fillable 和 guarded 到底该选哪个
直接说结论:用 fillable,别碰 guarded。Laravel 官方从 5.8 起就明确建议弃用 guarded(虽然没删),因为它的“黑名单”逻辑天然容易漏——只要新增一个字段没加进 guarded 数组,它就自动可批量赋值,等于裸奔。
而 fillable 是白名单,没列出来的字段一律被 Laravel 拦在 create()、update()、fill() 外面,安全边界清晰。
-
fillable是显式授权,新增字段必须主动加进去才可用 -
guarded是隐式放行,漏写一个字段就可能被恶意 POST 进来 - 如果模型字段多且常变,宁可花两秒补
fillable数组,也别赌自己不会漏guarded
怎么写 fillable 才不踩坑
常见错误是只写字段名,忽略数据库字段和模型访问器(accessor)/修改器(mutator)的差异。比如你定义了 getFullNameAttribute(),但 full_name 并不在数据库里——它不能放进 fillable,否则会报 MassAssignmentException 或静默失败。
真正能进 fillable 的,只有数据库真实存在的字段,以及你手动定义了 setXXXAttribute() 的字段(比如把 password 映射到 password_hash)。
- 检查迁移文件,确认字段是否真实存在(如
users表有email_verified_at,才写'email_verified_at') - 避免把
id、created_at、updated_at放进fillable——除非你真要手动控制这些值(极少见) - 如果用了
casts(如'options' => 'array'),字段名仍按原始列名写,不用加类型后缀
动态 fillable 怎么安全放开个别字段
有些场景确实需要临时放开——比如后台管理员编辑时允许改 is_active,但普通用户接口不能碰。这时候别改模型的 $fillable 静态数组,那会破坏全局约束。
正确做法是用 forceFill() 或显式指定字段:
php // 安全:只对特定字段强制填充,不影响 fillable 规则 $user->forceFill(['is_active' => true])->save(); // 更推荐:用 update() 显式传参,绕过 fillable 检查 $user->update(['is_active' => true]); // 错误:临时修改 $fillable(线程不安全,且可能污染后续请求) $user->fillable = array_merge($user->fillable, ['is_active']);
-
forceFill()会跳过所有fillable检查,适合可信上下文(如 console 命令或 admin 控制器) -
update()只跳过fillable,但仍受模型事件、cast、mutator 影响,语义更干净 - 永远不要在 request handler 里动态改
$fillable属性——Laravel 模型实例不是单例,但静态属性修改会影响整个进程生命周期
测试 fillable 是否生效的最快方式
别等上线出问题。在 Tinker 或单元测试里,用非法字段触发异常是最直接的验证:
php // 假设 User 的 fillable 是 ['name', 'email'] User::create(['name' => 'A', 'email' => 'a@b.c', 'admin_note' => 'xxx']); // 报错:Illuminate\Database\Eloquent\MassAssignmentException: admin_note
如果没报错,说明要么 admin_note 被误加进了 fillable,要么模型用了 guarded = [](等价于全放行)。
- 测试时优先用
create(),它最严格;fill()+save()行为一致 - 留意软删除字段(
deleted_at)——如果你没把它加进fillable,restore()会失败,这是个容易被忽略的点 - 第三方包(比如 spatie/laravel-permission)的关联字段通常不进你的
fillable,它们有自己的保护机制,别强行塞
白名单不是写完就完事,每次加字段、改迁移、接新 API,都得回头扫一眼 fillable 数组。漏掉的从来不是技术,是那半秒钟的确认。


















