修改器是模型中按set{Attribute}Attribute()命名规则定义的方法,仅在直接赋值时触发,需严格匹配大小写且必须操作$this->attributes数组,不适用于fill()或create()等批量操作。

修改器(Mutators)不是“设置”出来的,而是通过约定方法名在模型里写出来的——它只在你给模型属性赋值时触发,且必须严格匹配命名规则,否则完全不生效。
set{Attribute}Attribute() 方法必须拼写准确
修改器本质是模型类里的一个普通方法,Laravel 仅靠方法名识别它。常见错误是大小写或下划线错位:
-
setFirstNameAttribute()✅ 正确:数据库字段是first_name,首字母大写后去掉下划线 -
setfirstnameattribute()❌ 全小写,不触发 -
set_first_name_attribute()❌ 带下划线,不触发 -
setFirstNameAttr()❌ 缺少末尾ibute,不触发
注意:{Attribute} 部分对应的是你“想操作的属性名”,不是数据库字段名。比如你想让外部调用 $user->fullName = 'John Doe',就得写 setFullNameAttribute(),哪怕数据库里存的是 full_name 字段。
赋值时才执行,且只影响 $model->xxx = ... 场景
修改器不会在 create()、update() 或批量赋值(fill())中自动运行,除非你显式触发属性赋值:
-
$user->email = 'foo@bar.com';→ 触发setEmailAttribute() -
$user->fill(['email' => 'foo@bar.com']);→ 不触发,除非你在fill()前手动设属性 -
User::create(['email' => 'foo@bar.com']);→ 不触发,create()走的是直接插入,绕过访问器/修改器链
若需确保批量操作也走修改器,得改用 new Model([...])->save(),或在 creating/updating 事件里手动处理。
修改器内部必须操作 $this->attributes
修改器不能靠 return 改变值,而是要直接写进 $this->attributes 数组:
// ✅ 正确:把处理后的值塞进 attributes
public function setEmailAttribute($value)
{
$this->attributes['email'] = strtolower(trim($value));
}
// ❌ 错误:return 没用,数据库仍存原始值
public function setEmailAttribute($value)
{
return strtolower(trim($value)); // 这行完全无效
}
如果字段名和属性名不一致(如数据库存 salary_cents,对外叫 salary),就必须在修改器里明确指定键:$this->attributes['salary_cents'] = ...。漏掉这步,值就丢了。
密码哈希等敏感操作别依赖修改器自动触发
修改器看似方便,但容易被绕过。比如:
- 直接调用
$user->password = bcrypt('123')是 OK 的 - 但若前端传
password字段进Request,又在控制器里用$user->fill($request->all()),那setPasswordAttribute()根本不跑
更稳妥的做法是:在模型的 boot() 里监听 saving 事件,或统一在 FormRequest 中预处理,避免依赖修改器的“隐式触发”逻辑。这点在团队协作或遗留系统改造时尤其关键——没人能保证所有入口都走属性赋值。


















