thinkphp模型字段类型必须手动配置$type或$schema,否则默认按字符串处理;如datetime不配则无法转carbon对象,json不配$json数组则不自动编解码。

字段类型必须手动定义,ThinkPHP 不会自动推断数据库字段类型。 你看到的 datetime、json、float 等行为,全靠你在模型里显式配置 $type 或 $schema,否则数据库里存的是什么,PHP 拿到的就是什么字符串或整数。
为什么 $type 数组不能省略
ThinkPHP 的模型默认把所有字段当字符串处理。比如 MySQL 的 DATETIME 字段,不配 $type 就永远是字符串;JSON 字段不配就只是原始 JSON 字符串,不会自动 json_decode 成数组。
-
$type是最轻量的写法,只影响单个字段的读写转换,不影响字段元信息 - 必须写完整字段名,别名(如
create_time AS ctime)要单独配,否则无效 - 常见映射:
'create_time' => 'datetime'→ 转成Carbon对象;'config' => 'json'→ 自动编解码,但需同时确保$json = ['config']存在 - 如果字段实际是
TIMESTAMP类型,配'update_time' => 'timestamp'才会转成整型时间戳,配datetime可能报错或返回空
schema 和 fields_cache 到底该用哪个
$schema 是硬编码字段定义,fields_cache 是运行时生成的缓存——二者目标一致:避免首次模型实例化时查一次 SHOW COLUMNS。但使用逻辑完全不同。
- 启用
fields_cache需在config/database.php中设'fields_cache' => true(注意拼写是fields_cache,不是fileds_cache) - 执行
php think optimize:schema后,缓存文件生成在runtime/schema/下,Db 类和模型都生效 -
$schema必须写全表所有字段,漏一个就可能触发自动探测,导致缓存失效或类型错误 - 调试模式下
fields_cache默认不生效,所以开发时容易误以为“没起作用”,其实是被环境覆盖了
JSON 字段为什么有时不自动解码
ThinkPHP 对 JSON 的支持是“有条件启用”的,不是声明了字段类型为 json 就自动生效。
- 仅配置
'data' => 'json'在$type里不够,还必须把字段名加入$json数组:protected $json = ['data']; - 如果数据库字段类型不是原生
JSON(比如用TEXT存 JSON 字符串),也能工作,但要注意内容必须是合法 JSON,否则json_last_error()会静默失败 - 写入时传数组自动编码,但传字符串不会二次编码——也就是说,如果你手动
json_encode后再赋值,结果会变成双重编码 - 关联查询中(如
with('profile')),嵌套模型的$json不会自动继承,得各自定义
废弃字段和大小写敏感怎么避坑
历史表字段冗余或命名风格混乱时,$disuse 和 $strict 是刚需,但它们的行为很容易被忽略。
-
protected $disuse = ['status', 'type']后,这些字段在save()、create()、allowField()中彻底消失,连data()方法也不会透出 -
$strict = false允许模型接收非定义字段,但仅对data()和构造函数参数有效;__set()(即$user->xxx = 123)仍会抛InvalidArgumentException - MySQL 表字段是小写下划线(
create_time),但模型里用驼峰(createTime)访问时,必须确认开启了think\db\Connection的auto_convert,否则直接报错 - 字段名大小写在 Linux 环境下严格区分,Windows 下可能侥幸通过,上线后容易突然崩
最常被跳过的点:字段类型配置只在模型实例化后的读写流程中生效,Db::table()->where()->find() 这类原生查询完全绕过所有 $type 和 $json,该字符串还是字符串。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











