PHP PDO返回Decimal(10,2)值为字符串 如何配置转为浮点型
PDO DECIMAL字段自动转Float配置方案
可以通过PDO全局配置实现DECIMAL类型字段自动转换为float返回,无需为单表编写映射类,具体方案如下:
推荐方案:驱动原生配置(零额外业务代码)
PHP 5.3+版本默认使用的mysqlnd(MySQL原生驱动)原生支持类型自动转换,只需要在初始化PDO实例时关闭两个配置项即可全局生效:
$dbh = new PDO( 'mysql:host=127.0.0.1;dbname=your_db;charset=utf8mb4', 'your_username', 'your_password', [ PDO::ATTR_EMULATE_PREPARES => false, PDO::ATTR_STRINGIFY_FETCHES => false, ] );
PDO::ATTR_EMULATE_PREPARES => false:关闭PHP侧的模拟预编译逻辑,使用数据库端原生预编译,该配置本身也是推荐的安全配置,可以规避模拟预编译带来的SQL注入风险PDO::ATTR_STRINGIFY_FETCHES => false:关闭PDO自动将所有查询结果转为字符串的默认逻辑
两个配置同时生效后,查询返回的DECIMAL、FLOAT、DOUBLE类型字段会自动转为PHP的float类型,INT类型字段会自动转为int类型,所有查询通用,不需要修改现有业务代码。
兼容方案:自定义PDOStatement类(适配老旧驱动)
如果你的环境使用老旧的libmysqlclient驱动(无法通过上述配置实现自动类型转换),可以编写一次通用的PDOStatement子类全局处理类型转换,不需要针对每个表单独做映射:
class AutoTypeCastStatement extends PDOStatement { protected function __construct() {} public function fetch($mode = PDO::FETCH_DEFAULT, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) { $row = parent::fetch($mode, $cursorOrientation, $cursorOffset); if (!$row) { return $row; } // 可结合getColumnMeta接口判断字段真实类型做精准转换 // 通用逻辑示例:遍历结果对数值型字符串自动转float $process = function($item) { if (is_string($item) && is_numeric($item) && str_contains($item, '.')) { return (float)$item; } return $item; }; if (is_object($row)) { foreach ($row as $key => $val) { $row->$key = $process($val); } } elseif (is_array($row)) { $row = array_map($process, $row); } return $row; } } // PDO初始化后全局注册自定义语句类 $dbh->setAttribute(PDO::ATTR_STATEMENT_CLASS, [AutoTypeCastStatement::class]);
注意事项
- 正如你备注中提到的,PHP的float是二进制浮点类型,无法精确表示所有十进制小数,存在经典的
0.1 + 0.2 != 0.3精度误差问题。如果业务涉及金额、精密计量等对精度要求高的场景,即使自动转换为float,计算环节也建议使用BCMath、GMP等高精度数学库处理,避免精度损失引发业务错误。
内容的提问来源于stack exchange,提问作者DrDamnit
相关产品推荐
相关产品推荐

