之前同事在本地開發的時候,出現一個錯誤,如下圖所示:
字面意思就是反序列化錯誤,由此bug引申出來序列化和反序列化得應用,以及php array當key為string類型的數字值時,會發生什么情形。
先來看序列化
$str = [
1 => 2,
'str' => '字符串'
];
var_dump( serialize($str) );
//結果:serialize.php:7:string 'a:2:{i:1;i:2;s:3:"str";s:9:"字符串";}' (length=40)
//其中第一個a 表示數據是個array 2表明長度為2
//{} 中表示數組內容
//i:1;i:2
// i表示為key為int類型 1表示key值為1
// i表示為value為int類型 2表示value值為2
//s:3:"str";s:9:"字符串"
// s表示key為string類型 3表示key長度為3 "str"表示value值為"str"
// s表示value為string類型 9表示value長度為9 "字符串"表示value值為"字符串"
第二點PHP中數組,會把在常量PHP_INT_MAX(int最大值)范圍內的string類型的數值key自動轉換成int類型。若數組的key超出常量PHP_INT_MAX的值,則此key仍然保持string類型,反之,被轉換成int類型。
示例代碼如下:
var_dump( PHP_INT_MAX );
$str = [
'1' => 111,
'9223372036854775808' => 'PHP_INT_MAX + 1'
];
var_dump($str);
輸出結果如下圖:
可以看到 key為'1'時在輸出時變成了 1,而大于PHP_INT_MAX值得key依然是字符串。
回到標題反序列化錯誤的bug。
同事在本地開發的PHP_INT_MAX與測試環境不同,且在本地開發環境與測試環境存儲在同一數據中。這個時候,就會出現報錯的情況。即在本地開發中,可能PHP_INT_MAX較小,序列化會將數值轉換成s,而測試環境PHP_INT_MAX較大,序列化會將數值轉換成i。這個時候存儲不統一,就會造成在一個環境中序列化,在另一個環境反序列化,報標題的錯誤。