如何通过点表示法为jsonb字段赋值?Laravel操作报错未生效
问题现象
开发者尝试通过点表示法为模型关联的jsonb字段设置嵌套键值,执行如下代码:
$user = User::find(123); Illuminate\Support\Arr::set($user, 'foo.bar', 100);
运行代码后出现两类异常表现:
- 触发PHP运行时提示:
PHP Notice: Indirect modification of overloaded element of User has no effect in /Users/me/my-project/vendor/laravel/framework/src/Illuminate/Collections/Arr.php on line 575 - 最终输出的数组结构仅包含
["bar" => 100],$user模型实例上的foo字段值没有被实际修改,完全不符合预期。
问题根因
Arr::set的设计适用场景是操作原生PHP数组,直接传入Eloquent模型实例会触发两层逻辑错位:
- Eloquent模型不管是通过魔术方法
__get还是实现的ArrayAccess接口访问属性,拿到的json字段解码后的数组值都是按值传递的副本,和模型内部存储的属性不存在引用关联 Arr::set内部尝试通过数组写入的方式修改这个副本时,因为没有指向模型内部存储的引用链路,根本无法修改到模型实际持有的属性值,自然会触发“重载元素间接修改无效”的PHP提示- 整个修改过程作用在和模型完全隔离的临时变量上,最终形成的零散数组结构也是路径匹配错位的结果。
正确实现步骤
- 先从模型上读出对应json字段的现有值,生成独立的可操作数组
- 对这个独立数组使用
Arr::set通过点表示法设置嵌套键值 - 将处理完成的数组赋值回模型的对应字段,触发模型的修改状态标记
完整示例代码:
$user = User::find(123); // 取出foo字段的现有值,无值时给默认空数组 $fooData = $user->foo ?? []; // 对独立数组执行嵌套值设置 Illuminate\Support\Arr::set($fooData, 'bar', 100); // 将处理后的数组赋值回模型字段 $user->foo = $fooData; // 保存即可将嵌套值持久化到数据库jsonb字段 $user->save();
前置要求:需要在User模型中给
foo字段配置类型转换,即声明protected $casts = ['foo' => 'array'];,否则模型不会自动将赋值的数组序列化为可存储的json字符串。
内容的提问来源于stack exchange,提问作者DevonDahon
相关产品推荐
相关产品推荐

