int 型別float,導致精度遺失與鍵名衝突<?php
// 1. 正常範圍:字串鍵與整數鍵等價
$arr['123456'] = 'a';
$arr[123456] = 'b';
var_dump($arr); // 只剩一個元素,值為 'b' (後者覆蓋)
// 2. 超出 32 位整數 (假設 32 位環境)
$big = '2147483648'; // 2^31
$arr[$big] = 'x';
var_dump(array_keys($arr)); // 鍵名可能變成 float 2147483648.0 或負數
// 3. 超長數字字串 (20+ 位)
$huge = '12345678901234567890';
$arr[$huge] = 'y';
var_dump(array_keys($arr)); // 鍵名變成 0 !
// 4. 變數直接作鍵名
$val = 123456789012345; // PHP 解析為 float
$arr[$val] = 'z'; // 實際鍵名為 float
$arr["$val"] = 'w'; // 字串鍵名,不同鍵
var_dump(array_keys($arr)); // 兩個不同鍵
function arr_set(array &$arr, $key, $value) {
$arr[(string)$key] = $value;
}
function arr_get(array $arr, $key, $default = null) {
return $arr[(string)$key] ?? $default;
}
function arr_has(array $arr, $key) {
return array_key_exists((string)$key, $arr);
}
// 使用
$data = [];
arr_set($data, 12345678901234567890, 'safe');
arr_set($data, 'user_123', 'also safe');
echo arr_get($data, 12345678901234567890); // 'safe'
$json = '{"12345678901234567890": "value"}';
$arr = json_decode($json, true);
var_dump(array_keys($arr)); // 鍵名保持字串 "12345678901234567890" ✓
// 但 json_decode($json, false) 物件屬性名也為字串
$obj = json_decode($json);
echo $obj->{'12345678901234567890'}; // 需用大括號語法存取
MySQL BIGINT (64 位) 最大值 9,223,372,036,854,775,807 (19 位),在 32 位 PHP 環境下直接放入陣列鍵名會溢位。解決:查詢時 CAST(id AS CHAR) 或 PHP 端 (string)$row['id']。
| 情境 | 鍵名型別 | 風險 | 建議 |
|---|---|---|---|
| 短數字 (≤19位) | int | 低 | 可直接用,注意字串/整數等價 |
| 長數字 (>19位) | float/0 | 高 | 強制 (string)$key |
| 資料庫 BIGINT | int/float | 中 | 查詢轉字串或 PHP 轉字串 |
| JSON 解碼 | string | 無 | 安全,但物件存取需大括號 |
| 使用者輸入 ID | string | 低 | 保持字串,驗證格式後再用 |