为何查询结果列别名变为全小写而非预期的productId?
问题描述
测试环境配置:PHP 7 + Yii2 + MySQL 8
生产环境配置:PHP 5.6 + Yii2 + MySQL 8
执行以下查询代码时,生产环境运行正常,但测试环境抛出Undefined index: productId错误:
$cartItems = $cart->getItems()->select(['id', 'product_id as productId'])->andWhere(['product_id' => $productIds])->asArray()->all(); foreach ($cartItems as $cartItem) { $productDetail = $body[$cartItem['productId']]; // ⬅️ 错误触发位置 // ... }
打印测试环境的$cartItems结果,发现数组键为小写的productid,而非预期的驼峰式productId:
Array ( [0] => Array ( [id] => 123 [productid] => 456 ) )
尝试使用Expression方案后,问题仍未解决:
use yii\db\Expression; // 引入Expression类 $cartItems = $cart->getActiveItems()->select(['id', new Expression('product_id as productId')])->andWhere(['product_id' => $parentProductIds])->asArray()->all();
原因分析
核心问题出在MySQL的大小写配置差异:
- 生产环境的MySQL(搭配PHP5.6)大概率设置了
lower_case_table_names=0,会保留SQL查询中列别名的大小写格式; - 测试环境的MySQL 8默认配置可能为
lower_case_table_names=1,会强制将所有列名(包括别名)转换为小写,导致productId被转为productid。
Yii2在不同PHP版本下的数组键处理逻辑一致,不存在版本兼容问题,问题根源完全在数据库配置层面。
解决方案
方案1:修改MySQL配置(从根源解决)
修改测试环境MySQL的配置文件(Linux为my.cnf,Windows为my.ini),添加或调整参数:
lower_case_table_names=0
修改后重启MySQL服务,数据库会保留查询别名的大小写,productId即可正常作为数组键返回。
注意:该参数需在MySQL初始化前设置,若数据库已初始化,需先导出数据,重置数据库后再修改配置并重新导入数据,避免表名大小写冲突。
方案2:代码层面兼容(无需修改数据库)
如果无法调整数据库配置,可通过代码兼容处理:
- 方式一:统一使用小写键名访问
$productDetail = $body[$cartItem['productid']];
- 方式二:手动转换数组键格式
$cartItems = array_map(function($item) { return [ 'id' => $item['id'], 'productId' => $item['productid'] ]; }, $cartItems); // 后续正常使用$cartItem['productId']即可
- 方式三:利用Yii2的字段映射逻辑
$cartItems = $cart->getItems() ->select([ 'id', 'productId' => 'product_id' ]) ->andWhere(['product_id' => $productIds]) ->asArray() ->all();
这种方式通过直接指定键名productId映射原字段,Yii2会自动处理大小写问题,不受数据库配置影响。
内容的提问来源于stack exchange,提问作者Serum
相关产品推荐
相关产品推荐

