Laravel本地与生产环境响应数据类型差异问题排查请求
问题:Laravel项目本地与生产环境整数字段返回类型不一致
环境与问题描述
- 本地服务器:PHP 8.2.4 + Apache 2.4.56
- 生产服务器:PHP 8.2.9 + Apache 2.4.57
- 两台服务器Laravel项目文件完全一致
项目路由代码:
Route::get('users', function () { return \App\Models\User::all(); });
本地环境返回的JSON响应(test_integer为整数):
[ { "id": 1, "name": "test user", "test_integer": 505, "email": "sdsdsds", "email_verified_at": null, "created_at": null, "updated_at": null } ]
生产环境返回的JSON响应(test_integer为字符串):
[ { "id": 1, "name": "test user", "test_integer": "555", "email": "sdsdfdfdfsdsds", "email_verified_at": null, "created_at": null, "updated_at": null } ]
PDO驱动信息对比
本地开发服务器
- PDO支持:已启用
- PDO驱动:mysql, pgsql, sqlite
- pdo_mysql:
- MySQL驱动已启用
- Client API版本:mysqlnd 8.2.4
生产服务器
- PDO支持:已启用
- PDO驱动:mysql, odbc, pgsql, sqlite
- pdo_mysql:
- MySQL驱动已启用
- Client API版本:3.3.6
原因分析
核心差异在于PDO MySQL驱动的实现:
- 本地使用
mysqlnd驱动:这是PHP官方原生的MySQL客户端驱动,会根据数据库字段的实际类型自动将查询结果转换为对应PHP数据类型(比如数据库INT类型转为PHP整数)。 - 生产环境使用
libmysqlclient驱动:这是MySQL/MariaDB的C语言客户端库,默认会将所有数值类型查询结果以字符串形式返回,不会自动转换为PHP原生数值类型。你看到的3.3.6是MariaDBlibmysqlclient的版本号,并非mysqlnd版本。
即便生产环境安装了mysqlnd模块,但实际PDO连接使用的是libmysqlclient,这是类型不一致的根本原因。
解决办法
方法1:切换生产环境PDO驱动为mysqlnd
这是最彻底的解决方案,确保和本地环境驱动一致:
- 包管理工具(如Ubuntu/Debian
apt、CentOS/RHELyum/dnf):- 卸载基于
libmysqlclient的PHP MySQL扩展(例如php-mysql) - 安装
php-mysqlnd扩展 - 重启Apache服务
- 卸载基于
- 编译安装PHP:
- 重新编译时添加参数
--with-pdo-mysql=mysqlnd,替换默认的--with-pdo-mysql(默认指向libmysqlclient)
- 重新编译时添加参数
方法2:手动配置PDO属性强制类型转换
如果暂时无法切换驱动,可在Laravel数据库配置中强制PDO不将数值转为字符串:
编辑config/database.php,在mysql连接的options数组中添加配置:
'mysql' => [ // 其他配置项... 'options' => extension_loaded('pdo_mysql') ? array_filter([ PDO::ATTR_STRINGIFY_FETCHES => false, PDO::ATTR_EMULATE_PREPARES => false, ]) : [], ],
PDO::ATTR_STRINGIFY_FETCHES => false:禁止PDO将所有结果转为字符串PDO::ATTR_EMULATE_PREPARES => false:禁用预处理语句模拟,让驱动使用原生预处理,辅助类型正确解析
配置完成后清除Laravel配置缓存:
php artisan config:clear
内容的提问来源于stack exchange,提问作者Q8root
相关产品推荐
相关产品推荐

