Laravel 9新属性修改器赋值报错,Laravel 8旧写法正常,原因何在?
问题
Laravel 9+ 提供了新的属性修改器(mutator)格式,我按文档定义了如下访问器与修改器:
public function fullName(): Attribute { return Attribute::make( get: fn() => trim($this->first_name.' '.$this->last_name), set: function (?string $value) { $names = explode(' ', $value); $this->attributes['first_name'] = array_shift($names); $this->attributes['last_name'] = implode(' ', $names); } ); }
同时在模型中设置了:
protected $appends = ['full_name'];
但执行以下赋值保存操作时:
$model->full_name = 'John Doe'; $model->save();
出现错误:
Column not found: 1054 Unknown column 'full_name' in 'field list
而使用 Laravel 8 的旧写法定义修改器则无报错:
public function setFullNameAttribute(?string $value): void { $names = explode(' ', $value); $this->attributes['first_name'] = array_shift($names); $this->attributes['last_name'] = implode(' ', $names); }
为何新修改器格式无法正常赋值?
原因与解决方法
问题出在新的 Attribute 系统的默认行为上:
- 旧写法的修改器通过魔术方法(
setXXXAttribute)处理,Laravel 不会将full_name视为数据库实际列,只会触发对应的拆分逻辑。 - 新的 Attribute 定义方式默认会将属性标记为「可填充」,当你把
full_name加入$appends后,Laravel 执行save()时会错误地将这个虚拟属性当作数据库字段写入,因此抛出「列不存在」的错误。
解决方法很简单,只需在 Attribute 实例上调用 ->fillable(false),明确标记该属性不需要被填充到数据库:
use Illuminate\Database\Eloquent\Casts\Attribute; public function fullName(): Attribute { return Attribute::make( get: fn() => trim($this->first_name.' '.$this->last_name), set: function (?string $value) { $names = explode(' ', $value); $this->attributes['first_name'] = array_shift($names); $this->attributes['last_name'] = implode(' ', $names); } )->fillable(false); // 关键:禁止该属性被当作数据库列处理 }
修改后,赋值 $model->full_name = 'John Doe' 时只会触发 set 方法的拆分逻辑,将值存入 first_name 和 last_name 字段,不会再尝试写入 full_name 虚拟属性。
内容的提问来源于stack exchange,提问作者eComEvo
相关产品推荐
相关产品推荐

