thinkphp 6 读取 json 字段需在模型中显式声明 $json 属性,如 protected $json = ['config']; 否则返回字符串而非数组;该配置仅对模型查询生效,且不可与 withattr 混用,否则导致重复解码为 null。

ThinkPHP 6 读取数据库 JSON 字段时返回字符串而非数组,不是数据坏了,是框架默认不自动反序列化 —— 即使字段类型是 MySQL 的 JSON,TP6 仍当它是普通字符串处理。关键在模型配置,不是改数据库或写额外 decode。
必须在模型中声明 $json 属性
TP6 不靠数据库类型推断,只认模型里的显式声明:
- 在对应模型类中添加:
protected $json = ['config', 'setting', 'extra']; - 字段名必须与数据库列名完全一致(大小写敏感),不能带表前缀或点号(如
user.info不支持) - 该配置仅对
find()、select()、get()等模型查询生效;用Db::table()直接查会完全跳过此机制
避免和 withAttr 冲突
两者都做字段转换,但机制不同,混用会导致重复解码或覆盖:
- 若已配
$json = ['data'],就不要同时写$withAttr = ['data' => 'json_decode'] - 重复调用
json_decode作用在数组上,结果为null,数据丢失 - 推荐优先用
$json:轻量、统一、符合 TP 设计;仅当需 fallback 默认值、兼容旧格式等定制逻辑时才选withAttr
快速定位是否生效
出错时别猜,直接验证运行时类型:
- 在报错行前加:
var_dump(gettype($model->config), $model->config); - 若输出
string和一串带引号的 JSON(如"{\"name\":\"张三\"}"),说明$json没配对或字段名拼错 - 检查控制器是否用了模型实例(如
User::find(1)),而非Db::name('user')->find()
写入无需手动 json_encode
只要字段在 $json 列表里,TP6 会自动处理:
- 传数组进去:
$user->config = ['theme' => 'dark', 'lang' => 'zh']; - 保存时自动
json_encode,且默认带上JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES,中文和斜杠不会乱码或转义 - 不用在控制器或模型里手动调
json_encode,否则会变成双重编码
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











