用 new static($array)可触发creating事件并自动填充created_at,fill()则更轻量但不触发事件;反序列化时需注意cast、关系和访问器无法自动还原。

用 fill() 还是 new static()?看你要不要触发事件和验证
直接 new 一个模型实例再 fill(),和用 new static($array) 构造,行为差异很大。前者不走构造函数的属性赋值逻辑,也不触发 creating、updating 等事件;后者会走完整初始化流程,但默认跳过验证(除非你手动调用 validate())。
- 要复现“创建新记录”的完整生命周期(比如自动填充
created_at、触发creating事件)→ 用new static($array) - 只是临时组装数据做计算或预处理,不打算保存 →
fill()更轻量,也更可控 - 如果数组里有非 fillable 字段,两种方式都会被
$fillable或$guarded拦住,别指望绕过模型白名单
toArray() 反向还原时丢失关系和访问器怎么办
模型调用 toArray() 后,关系(如 posts)和访问器(如 full_name)虽然能出现在数组里,但反向重建时它们只是普通键值,不会自动转成关联实例或重新计算。Laravel 不会、也不能凭空恢复这些逻辑。
- 关系数据需手动重新加载:
$model->setRelation('posts', collect($data['posts'])->map(fn($p) => Post::hydrate([$p]))); - 访问器值无法“反向生成”,只能当普通字段塞进去:
$model->full_name = $data['full_name'];—— 但这只是静态快照,后续改first_name不会联动更新 - 若依赖关系做业务判断,别反序列化数组了,直接查库:
Post::with('user')->find($id)更可靠
从 JSON 字符串反序列化模型容易踩的类型坑
JSON 解析后所有数字都是 float 或 int,字符串是 UTF-8,但模型字段可能设了 $casts = ['price' => 'decimal:2'] 或 'published_at' => 'datetime'。原生 json_decode() 不会触发 cast,必须让 Laravel 的模型机制介入。
- 错:先
json_decode($json, true)再传给模型 → 所有 cast 和日期转换失效 - 对:用
Model::fromArray(json_decode($json, true))或直接new Model(json_decode($json, true))→ cast 和getDateFormat()才生效 - 特别注意布尔字段:JSON 里的
true经json_decode是 PHPtrue,但若字段 cast 为'bool',模型能识别;若 cast 为'integer',就得确保原始 JSON 里是1/0,否则存库变1(PHP true 强转 int 就是 1)
批量重建模型时性能和内存怎么控
用 Model::hydrate($arrayOfRows) 是最高效的方式,它跳过构造函数和事件,只做属性赋值。但如果你用循环 new + fill,每轮都触发模型初始化,开销翻倍,尤其带大量访问器或复杂 get* 方法时。
- 100 条以内:用
new Model($row)或Model::make($row)都行 - 1000+ 条:必须用
Model::hydrate($rows),它返回的是已赋值的模型集合,不走事件、不验证、不 cast 关系 - hydrated 模型的
$casts仍生效,但关系和访问器不会自动补全 —— 别指望 hydrate 做“全自动还原” - 如果数组来自外部 API,字段名和数据库列不一致,先用
array_map映射好再 hydrate,别在模型里靠$casts或访问器硬扛











