ThinkPHP模型需手动配置$type和$json属性实现字段类型转换与JSON自动序列化:'create_time'=>'datetime'转Carbon对象,'status'=>'boolean'转布尔值,'extra'=>'json'配合$json=['extra']实现JSON存取,逗号字符串用访问器处理。

刚写完一个用户模型,查出来的create_time是字符串、status是数字0或1、extra字段存的是JSON却显示成原始字符串——这不是数据库问题,是ThinkPHP模型没配字段类型转换和JSON自动序列化。
配置字段类型转换让时间、布尔、浮点自动转目标类型
ThinkPHP不会读取数据库schema自动推断类型,所有转换必须手动声明在模型类中。
第一步:打开你的模型类(如app\model\User.php),在类内部顶部添加protected $type属性:
【'create_time' => 'datetime'】 这样查出来的create_time就是Carbon对象,能直接调用->format('Y-m-d')或->diffForHumans();如果写成'timestamp',得到的就是整型秒级时间戳。
立即学习“PHP免费学习笔记(深入)”;
第二步:为布尔字段加转换规则,例如status字段存0/1,写'status' => 'boolean'——注意它只对0、1、'0'、'1'、true、false生效,其他值(比如'on')不会转,仍返回原值。
第三步:浮点字段如price,写'price' => 'float',别用'double',后者不被识别;整型字段如id,写'id' => 'integer'(不是'int')。
字段名必须和数据库列名完全一致,大小写、下划线都不能错;$type必须是protected,写成public或没声明修饰符就无效。
JSON字段自动序列化:必须$type和$json同时存在
只配$type = ['extra' => 'json'],extra字段读出来还是字符串;只配$json = ['extra'],save()时会报Array to string conversion错误——两者缺一不可。
方法一:在模型类中同时声明两个属性:
protected $type = ['extra' => 'json'];
protected $json = ['extra'];
这样赋值$model->extra = ['theme' => 'dark']; $model->save();时,框架会自动json_encode写入;查询时自动json_decode成数组。
方法二:若需控制解码目标类型,加$jsonType:
protected $jsonType = ['extra' => 'object']; → $model->extra返回stdClass对象,支持->theme访问
protected $jsonType = ['extra' => 'array']; → 返回关联数组,支持$extra['theme']
【字段值为null或空字符串时,$model->extra直接返回null,不是[]】 业务逻辑里要自行判断并补默认值,比如$this->extra ?: []。
逗号分隔字符串转数组?别硬套json类型
数据库字段tags存的是"php,mysql,js"这种字符串,不能在$type里写'tags' => 'json'——那会因解析失败返回null。
正确做法是定义自定义访问器:
public function getTagsAttr($value)
{
if (is_string($value) && !empty($value)) {
return explode(',', $value);
}
return [];
}
public function setTagsAttr($value)
{
if (is_array($value)) {
return implode(',', $value);
}
return $value;
}
这样$model->tags就能读出数组、写入时自动转回逗号字符串,无需改动数据库结构。
数组字段修改后必须整体赋值才能保存
ThinkPHP不监听数组内部变化,$user->extra['name'] = 'a'这行代码执行后,save()不会更新extra字段。
第一步:取出当前值
$extra = $user->extra;
第二步:修改数组内容
$extra['name'] = 'a';
第三步:整体重新赋值并保存
$user->extra = $extra;
$user->save();
如果extra字段可能为null或非法JSON,先用json_decode($user->getData('extra'), true)拿原始字符串再操作,避免触发异常。



















