发布于2026-07-06 阅读(0)
扫一扫,手机访问
先说说一个常见问题:数据库字段明明存的是 JSON 格式,代码里也写了 foreach,结果直接报错 Invalid argument supplied for foreach()。这其实不是框架出了 bug,而是 TP6 默认并不会自动帮你把 JSON 字符串转成数组或对象——哪怕你在数据库里把字段类型设成了 JSON,它取出来还是个带着引号的字符串。
错误现象很典型:查出来的字段值是 "{\"name\":\"张三\",\"age\":25}" 这样的带引号字符串,一用 foreach 就崩溃;或者试图用 $user->config->name,结果提示 Trying to get property 'name' of non-object。
根本原因在于,TP6 并不会因为 MySQL 字段类型是 JSON 就自动执行 json_decode。你必须显式告诉模型“这个字段存的是 JSON”。
protected $json = ['config', 'setting'];,注意值必须是数据库字段名(字符串),不能写嵌套路径如 'config.name'。$json 只对 select()、find() 等查询结果生效;写入数据时 TP 会自动 json_encode,无需手动处理。field(['id', 'name']) 却没包含 config),那 $json 就不会触发。withAttr 一起用导致重复 decode 或数据变 null另一个坑是:字段值变成 null,或者结构异常(本该是数组却显示成字符串)。日志不报错,业务却莫名其妙崩了。
典型冲突写法是这样的:
protected $json = ['setting']; protected $withAttr = ['setting' => 'json_decode'];
执行流程很容易分析:TP 先按 $json 做一次 json_decode → 得到 PHP 数组 → 再进 withAttr,又对这个数组调一次 json_decode → 返回 null。
$json 是模型级声明,走内置 JSON 处理链;withAttr 是运行时获取器,优先级更高,会直接接管字段值。$json 更轻量、符合 TP 设计意图;withAttr 适合需要 fallback、兼容旧格式等定制场景。withAttr,记得删掉对应字段的 $json 声明。toArray() 有转换但 getAttr() 获取器里没生效第三种情况:调用 $model->toArray() 时 JSON 字段正常转成了数组,但自定义获取器 getSettingAttr() 里拿到的 $value 还是原始字符串。
原因在于 $json 的反序列化发生在模型属性赋值阶段,而 getAttr() 是在取值时才执行,它拿到的是已经处理过的值——但前提是没被覆盖。如果你写了 getSettingAttr(),TP 就不会走 $json 流程,而是直接把原始字段值传进来。
json_decode($value, true)。is_string($value) && !empty($value) 再 decode。$json 对 toArray()、toJson() 有效,但对 getAttr()、setAttr() 不自动叠加,这个细节容易忽略。总结一下,最容易被绕开的是:以为数据库字段类型设为 JSON,TP 就会自动处理;实际上它只认模型里的 $json 声明。字段名拼错、withAttr 和 $json 并存、获取器里没手动 decode——这三个地方出问题,十有八九就是 JSON 字段报错的根源。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8