yii 查询结果保持数据库原始类型,int字段可能返回字符串,需在afterfind()中手动转换;tinyint(1)被误判为boolean时应改用tinyint(2)或覆盖gettableschema();datetime字段需用getter转datetime对象;自定义类型映射须确保读写两端一致。

Yii 模型里 int 字段存了字符串,查出来还是 string?
不是数据库没转,是 Yii 默认不自动类型转换——它只在保存(save())时按 schema 做一次 cast,查询结果直接映射为 PDO 返回的原始类型(比如 MySQL 的 TINYINT 可能是 string)。尤其用 find()->asArray(false)(即 ActiveQuery 默认行为)时,ActiveRecord 实例字段值就是原样塞进去的。
常见错误现象:$model->status 显示为 "1"(字符串),但你写了 public int $status;,PHP 8.0+ 严格模式下直接报 TypeError;或者做 match、=== 判断时失败。
- 必须在模型类中显式启用类型转换:重写
attributes()方法,把字段加进typecastAttributes配置 - 或更常用:在
init()中调用$this->loadDefaultValues(true),但这只对 null/默认值生效,不解决已有数据 - 真正可靠的做法:在
afterFind()里手动 cast,例如$this->status = (int)$this->status;
MySQL TINYINT(1) 被 Yii 当成 boolean 怎么办?
Yii 的 Schema 类会把 TINYINT(1) 自动识别为 boolean 类型,即使你数据库里存的是 0/1/2 这样的状态码。一旦字段类型被标为 boolean,ActiveRecord 就会在读取时强制转成 true/false,丢失中间值。
使用场景:状态字段如 status TINYINT(1) DEFAULT 0 COMMENT '0待处理,1已通过,2已拒绝' —— 这种不能当布尔用。
- 建表时避开
TINYINT(1),改用TINYINT(2)或SMALLINT,Schema 就不会误判 - 如果无法改库,在模型里覆盖
getTableSchema(),手动修正列类型:$schema->columns['status']->type = 'integer'; - 注意:修改
getTableSchema()后,save()时的类型校验也会按新类型走,别漏掉验证规则
datetime 字段返回 string 而不是 DateTime 对象?
Yii 默认不自动把时间字段转成 DateTime 实例,哪怕你在模型里声明了 public DateTime $created_at;。查询结果仍是字符串(如 "2024-05-20 14:30:00"),PHP 严格类型检查下直接报错。
性能影响:每次访问都 new 一个 DateTime 是可接受的,但反复 parse 同一字段会浪费 CPU;用 getter 封装最轻量。
- 推荐做法:定义 getter,例如
public function getCreatedAt(): DateTime { return new DateTime($this->created_at); } - 避免重写
afterFind()把所有时间字段都转对象——内存占用翻倍,且可能和批量查询冲突 - 如果要用
asArray(true),那就别指望对象,老老实实处理字符串格式
自定义类型映射后,save() 报 InvalidParamException?
当你手动改过 getTableSchema() 或在 attributes() 里指定了类型,但数据库字段实际长度/精度不匹配时,Yii 在 save() 前的参数绑定阶段就会抛出 InvalidParamException: Data type mismatch。
容易踩的坑:只改了读取逻辑,忘了写入路径也要对齐。比如把 DECIMAL(10,2) 强制设为 float,但用户输入了 "123.456"(三位小数),PDO 绑定时发现精度超限就炸了。
- 检查
yii\db\Schema::getColumnType()返回值是否与 DB 实际一致(可用var_dump($model->getTableSchema()->columns['price'])确认) - 写入前做截断或四舍五入:在
beforeSave()里处理,而不是依赖框架自动 cast - 测试边界值:插入
99999999.99和0.001,看会不会静默丢精度
类型映射不是设完就完事,读写两端都要对得上,尤其是 decimal、enum、json 这类易出错的类型。数据库 schema 和 PHP 类型声明之间那层薄薄的映射,稍有偏差,问题就藏在运行时里,很难一眼看出。











