thinkphp模型中json字段默认不自动转数组,必须显式声明$json = ['extra']或通过getextraattr手动处理;否则$model->extra始终返回字符串。

JSON字段在模型里不会自动转数组,必须显式声明 $json 或用 getAttr 手动处理,否则 $model->extra 拿到的永远是字符串。
为什么 $model->extra 返回字符串而不是数组
ThinkPHP 默认把所有字段当原始值读取,哪怕数据库字段类型是 JSON,模型层也不会自动 json_decode。不配置就等于没启用 JSON 解析能力。
- TP6 必须在模型中声明
protected $json = ['extra'];,字段名要和数据库列名完全一致 - TP8 虽默认对 JSON 类型字段做 decode,但仅限
find()/select()查询结果;$model->getData('extra')或直接__get仍可能返回原始字符串 - 如果字段值是
null或空字符串,$model->extra就是null,不是空数组——得自己补默认值,比如return $value ?: []; - 字段类型不是
JSON(比如是VARCHAR或TEXT),$json声明也无效,只能靠getExtraAttr
用 getAttr 处理 JSON 字段的三个关键点
当 $json 不适用(比如字段名含点号 settings.theme,或需要兼容旧版 TP5),就得写 getExtraAttr。但别直接 json_decode($value) 就完事。
使用 JSON Schema 验证 JSON 数据,从示例 JSON 生成 schema,并将其转换为 TypeScript 接口、Python 数据类或 Markdown 文档。
- 先判空:
if (empty($value)) return [];,否则json_decode(null)返回null,后续isset($data->key)会报错 - 校验合法性:
$parsed = json_decode($value, true); if (json_last_error() !== JSON_ERROR_NONE) { return []; } - 别覆盖原始值:
getAttr只负责“读取时转换”,不影响$model->getData('extra')获取原始字符串,这是调试和写入的基础
修改 JSON 字段内容后怎么保存生效
很多人写 $model->extra['status'] = 'done'; 就以为存进去了,其实不会——ThinkPHP 不监听数组内部变化,只检测字段级赋值。
- 必须整体重新赋值:
$data = $model->extra; $data['status'] = 'done'; $model->extra = $data; $model->save(); - 如果用了
allowField(true)且前端传的是 JSON 字符串,得先json_decode($input['extra'], true)再塞进data(),否则会双层编码 - 用
whereJsonContains等查询方法前,确认 MySQL ≥ 5.7 且字段类型真是JSON,否则 SQL 直接报错,不是模型配置问题
toJson() 输出时 JSON 字段变回字符串?
调 $model->toJson() 发现 extra 字段又成了字符串,不是数组——这不是 bug,是序列化过程绕过了 getAttr,直接读了原始数据。
-
toJson()底层调toArray(),而toArray()默认不触发getAttr(除非字段在append里) - 想让 JSON 字段在 JSON 输出里保持结构,要么加到
append并配getExtraAttr,要么重写toArray(),在里面手动json_decode - 更稳妥的做法:金额/日期等字段统一用
getAttr控制展示,JSON 字段只做存储载体,业务逻辑层再解码——避免模型层过度承担解析责任
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!










