
当商品编码为纯数字(如“001”)时,PHP 会自动将其转为整数类型,导致键名丢失前导零、发生类型隐式转换,进而使 in_array() 判重失效,造成同一商品被多次添加。
当商品编码为纯数字(如“001”)时,php 会自动将其转为整数类型,导致键名丢失前导零、发生类型隐式转换,进而使 `in_array()` 判重失效,造成同一商品被多次添加。
该问题的核心在于 PHP 的数组键类型自动转换与in_array() 的松散比较机制共同引发的逻辑缺陷。
首先看原代码关键问题:
$array_keys = array_keys($_SESSION["shopping_cart"]);
if(in_array($array_keys, $code)) { ... }这段代码存在两个严重错误:
-
in_array($array_keys, $code)参数顺序颠倒 —— 应为in_array($code, $array_keys); - 更关键的是:
$array_keys是一个索引数组(如['K001', '001']),而$code是字符串(如'001'),但若数据库中code字段为INT类型或未加引号的数字,PHP 会将'001'自动转为整数1,同时array_keys()返回的键在存储时也已被转为整数1(而非字符串'001'),导致后续所有形如'001'、'01'、'1'的编码全部映射到同一数组键1,彻底破坏唯一性。
✅ 正确解决方案需从数据源头和判重逻辑两方面修复:
1. 确保商品编码始终为字符串(保留前导零)
无论数据库字段类型如何,读取后立即强制转为字符串,并补零(如需统一长度):
$code = (string) $row['code']; // 强制字符串化 // 若需固定3位(如 '1' → '001'),使用: $code = str_pad((string) $row['code'], 3, '0', STR_PAD_LEFT);
⚠️ 注意:
strval()在面对整数001(实际存储为1)时仍会输出'1',无法恢复原始格式。因此数据库中应将code字段设为VARCHAR,并确保插入时以字符串形式写入(如'001'而非001)。
2. 修复判重逻辑:用 isset() 替代 in_array()
数组键的精确存在性判断,应使用 isset() —— 它严格匹配键名与类型,且性能更优:
$cartArray = [
$code => [
'name' => $name,
'code' => $code,
'price' => $price,
'quantity' => 1,
'image' => $image
]
];
if (empty($_SESSION['shopping_cart'])) {
$_SESSION['shopping_cart'] = $cartArray;
$status = "<div class='box'>Product is added to your cart!</div>";
} else {
// ✅ 正确判重:检查键是否存在(字符串精确匹配)
if (isset($_SESSION['shopping_cart'][$code])) {
$status = "<div class='box' style='color:red;'>Product is already added to your cart!</div>";
} else {
$_SESSION['shopping_cart'] = array_merge(
$_SESSION['shopping_cart'],
$cartArray
);
$status = "<div class='box'>Product is added to your cart!</div>";
}
}3. 进阶建议:统一编码规范 + 防御性处理
- 数据库设计:
products.code必须为VARCHAR(N),禁止使用INT或TINYINT; - 输入校验:前端与 API 层对
code做非空、长度、正则(如/^[a-zA-Z0-9]{1,20}$/)校验; - 调试技巧:添加日志验证类型与值:
error_log("Code value: '{$code}', type: " . gettype($code)); error_log("Cart keys: " . json_encode(array_keys($_SESSION['shopping_cart'])));
通过以上三步,即可彻底解决纯数字商品编码(如 '001')在购物车中重复添加的问题,同时提升系统健壮性与可维护性。

















