thinkphp 中“array”类型实为 json 字符串的自动编解码简写,底层仍是字符串字段;必须同时配置 $json 和 $type 且字段名严格一致(含下划线),否则不生效;推荐 mysql 5.7+ 使用原生 json 类型并设 $type 为 'json'。

ThinkPHP 里没有真正的“数组字段类型”,所谓 array 类型只是对字符串字段做自动 json_decode/json_encode 的简写,底层仍是 VARCHAR 或 TEXT —— 直接用它存复杂嵌套结构,查出来是 null 或空数组,八成是 JSON 格式不合法或字段没配对。
为什么 $type = ['config' => 'array'] 有时不生效
这是最常踩的坑:ThinkPHP 的 array 类型依赖数据库字段内容为合法 JSON 字符串,但不会校验、也不会自动修复。一旦存入的是 PHP 序列化格式(如 a:1:{s:3:"key";s:5:"value";})、带中文引号的 JSON、或 MySQL 自动转义过的字符串,读取时 json_decode 失败就静默返回 null 或空数组。
- 检查原始数据:
SELECT config FROM user WHERE id = 1,确认结果是标准双引号 JSON(如{"theme":"dark","lang":"zh-CN"}),不是单引号、没换行、没不可见字符 -
$type只影响模型读取时的自动转换,写入仍靠你手动json_encode或靠$json属性(见下一条) - MySQL 5.7+ 建议直接用原生
JSON类型字段,并把$type改成'json',更安全;'array'仅适用于老版本或兼容场景
$json 和 $type 必须同时配,缺一不可
很多人只写 protected $json = ['config'],以为就能自动编解码——不行。ThinkPHP 要求 $json 和 $type 同时存在且字段名一致,才会启用 JSON 自动处理流程。否则,即使字段存的是 JSON 字符串,读出来还是原始字符串。
- 正确写法:
protected $json = ['config']; protected $type = ['config' => 'json'];
- 错误写法:
protected $json = ['config'];(无$type)→ 读出来是字符串;protected $type = ['config' => 'array'];(无$json)→ 不触发 JSON 编解码逻辑 -
'json'和'array'在这里效果相同,但推荐用'json',语义清晰,且与 MySQL 原生 JSON 类型对齐
关联模型里 toArray() 不自动处理子项的 array 字段
当你调用 $user->with(['profile'])->toArray(),即使 Profile 模型定义了 $json = ['settings'] 和 $type = ['settings' => 'json'],默认也不会对 profile.settings 做自动解码——因为 toArray() 对关联模型走的是数据集序列化路径,不重新实例化子模型。
- 临时解决:显式调用子模型的
toArray():$user->profile->toArray() - 稳妥做法:在关联查询时用闭包预处理:
$user = User::with(['profile' => function($q) { $q->hidden(['id', 'user_id']); }])->find(1); // 然后手动处理 $data = $user->toArray(); if ($user->profile) { $data['profile'] = $user->profile->toArray(); } - 避免嵌套陷阱:如果
profile.settings是 JSON 字段,别指望它在父级toArray()中自动变成 PHP 数组;必须确保子模型被完整实例化并触发其类型转换逻辑
用 append 追加字段时,array 类型不自动生效
append 添加的字段(比如 getFullnameAttr)走的是获取器逻辑,不受 $type 控制。如果你在获取器里返回的是 JSON 字符串,而希望它被自动转成数组,得手动加 json_decode。
- 错误示范:
public function getSettingsAttr($value) { return $value; // $value 是字符串,不会被 $type 处理 } - 正确写法:
public function getSettingsAttr($value) { return json_decode($value, true) ?: []; } - 注意:
append字段不会参与数据库写入,所以也不存在$type写入转换;所有处理都得在获取器里显式完成
真正容易被忽略的是字段名大小写和下划线风格——数据库字段是 user_config,你就得在 $json 和 $type 里写 'user_config',写成 'userConfig' 或漏掉下划线,整个自动转换链就断了,还不报错。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











