Yii2的asArray()返回字符串类型字段,因其绕过AR类型转换,直接返回PDO原始结果;推荐查询后依getTableSchema()手动转换,或改用AR实例获取自动类型转换。

Yii2 的 asArray() 查询结果中字段全是字符串,是因为 PDO 默认将所有数据库字段以字符串形式返回,即使数据库里是整数、布尔或时间类型。虽然 AR 层(ActiveRecord)在模型中定义了类型和规则,但 asArray() 绕过了 AR 实例化过程,不触发属性类型转换和 getter/setter 逻辑,所以原始 PDO 结果直接返回,未做任何 PHP 类型还原。
明确 asArray() 的行为边界
asArray() 的设计目标就是轻量、快速地返回原始数据数组,不加载模型对象、不调用属性类型转换、不执行验证或格式化。它本质是 createCommand()->queryAll() 的封装,底层依赖 PDO 的 fetchMode 配置(默认为 PDO::FETCH_ASSOC),而 PDO 本身不进行 PHP 类型映射(除非显式启用 PDO::ATTR_STRINGIFY_FETCHES = false 且驱动支持,但 MySQL 基本不生效)。
在查询后手动类型转换(推荐)
若需保持 asArray() 的性能优势,又需要正确类型,可在查询后对关键字段做一次轻量转换。利用模型的 schema 信息自动推导类型:
- 调用
MyModel::getTableSchema()获取字段元数据,其中$column->phpType给出预期 PHP 类型(如'integer'、'boolean'、'double'、'string'等) - 遍历结果数组,按字段名匹配 schema,对
phpType非'string'的字段执行强制转换 - 示例代码片段:
// $rows = MyModel::find()->asArray()->all();
$schema = MyModel::getTableSchema();
foreach ($rows as &$row) {
foreach ($schema->columns as $name => $column) {
if (isset($row[$name]) && $column->phpType !== 'string') {
switch ($column->phpType) {
case 'integer': $row[$name] = (int)$row[$name]; break;
case 'boolean': $row[$name] = filter_var($row[$name], FILTER_VALIDATE_BOOLEAN); break;
case 'double': $row[$name] = (float)$row[$name]; break;
case 'null': $row[$name] = $row[$name] === '' || $row[$name] === null ? null : $row[$name]; break;
}
}
}
}
改用 ActiveRecord 实例(适合小数据量或需完整逻辑场景)
如果业务需要验证、关系、事件、getter/setter 或类型安全保障,就不要强求 asArray()。直接去掉 asArray(),用标准 AR 查询:
$models = MyModel::find()->where(...)->all();- 每个
$model的属性已按phpType自动转换,且支持getAttribute()、toArray()等方法 - 如只需数组结构,最后调用
ArrayHelper::toArray($models)或array_map(fn($m) => $m->toArray(), $models)
数据库连接层微调(谨慎使用)
部分 PDO 驱动(如 PostgreSQL)支持 PDO::ATTR_EMULATE_PREPARES = false + 启用原生类型,但 MySQL 官方驱动长期不支持可靠类型返回。不建议依赖此方式,兼容性和稳定性差。可检查当前配置:
- 确认
'emulatePrepare' => false已设(Yii2 默认为true) - 但即便设为
false,MySQLi/PDO_MYSQL 仍几乎总是返回字符串 —— 这是驱动限制,非 Yii 问题


















