Eloquent模型默认值不能依赖$attributes数组设空字符串或null,因其仅在数据库字段为NULL且未赋值时生效;应使用访问器、creating事件或请求预处理实现可靠默认值。

Eloquent 模型的属性默认值不能靠 $attributes 数组直接设“空字符串”或 null 来兜底——它只在数据库字段为 NULL 且未显式赋值时生效,一旦你调用 $model->name = '' 或 fill([]),这个默认值就彻底失效了。
为什么 $attributes 在大多数场景下不生效
这个数组本质是“数据库字段初始值”,不是“模型属性默认值”。它只影响 new Model() 实例化后、尚未调用 fill() 或赋值前的原始状态。一旦执行以下任一操作,$attributes 就被覆盖:
-
$user = new User(); $user->save();—— 此时$attributes会写入数据库,但后续$user->name读取的是 DB 值(哪怕为空字符串) -
$user = User::make(['email' => 'a@b.c']);——make()会合并传入数据,忽略$attributes中未提供的字段 -
$user->fill([]);—— 空数组也会触发属性重置逻辑,清空所有未传字段(包括本该用默认值的)
真正可控的默认值方案:使用 getAttributes() + isset() 判断
在访问属性前做运行时兜底,是最可靠的方式。适合需要“读取即默认”的字段,比如 status、role、avatar:
class User extends Model
{
protected $casts = [
'status' => 'string',
];
public function getStatusAttribute($value)
{
return $value ?? 'active';
}
public function getAvatarAttribute($value)
{
return $value ?: 'https://ui-avatars.com/api/?name=' . urlencode($this->name ?? 'User');
}
}
注意:?? 处理 null,?: 处理 falsy 值(如空字符串、0、false),按需选择。
批量设置默认值:用 boot() + creating 事件
如果目标是“新建记录时数据库写入默认值”,必须在保存前干预。仅靠 $attributes 不足以应对 fill() 或 API 请求中缺失字段的情况:
-
creating事件只在save()/create()时触发,不影响内存模型状态 - 务必用
! isset($this->attributes['field'])判断,而不是empty()—— 否则0或false会被误覆盖 - 避免在
updating中设默认值,否则每次更新都会强行重写字段
protected static function boot()
{
parent::boot();
static::creating(function ($model) {
if (! isset($model->attributes['status'])) {
$model->status = 'active';
}
if (! isset($model->attributes['sort_order'])) {
$model->sort_order = 0;
}
});
}
API 请求中缺失字段的默认填充:用 fill() 前预处理 request()->all()
Laravel 的 fill() 和构造函数不会自动补全缺失键,必须手动 merge 默认值。别在控制器里硬编码,抽成可复用方法:
public function store(Request $request)
{
$data = array_merge([
'status' => 'pending',
'is_verified' => false,
], $request->only(['name', 'email', 'bio']));
$user = User::create($data);
}
更健壮的做法是封装到 Request 类或 Form Request 的 validated() 之后:
public function rules()
{
return [
'name' => 'required|string',
'email' => 'required|email',
];
}
protected function prepareForValidation()
{
$this->mergeIfMissing([
'status' => 'pending',
'is_verified' => false,
]);
}
真正麻烦的不是怎么设默认值,而是默认值该在哪一层生效:数据库迁移里设 DEFAULT?模型访问器里兜底?创建事件里注入?还是请求层预填充?选错位置,一个空字符串就能让整个业务逻辑走偏。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











