PHP 作為弱型別語言,其無縫的隱式型別轉換背後,仰賴 zval 結構統一管理所有變數值。以 PHP 5.2 為例,zval 核心欄位包含 value(實際數值)、refcount(引用計數)、type(作用型別)、is_ref(是否引用)。其中 value 為聯合體 zvalue_value,重點在於兩個成員:
long lval:長整數,長度隨編譯器與作業系統字長而定(32 或 64 位元)。double dval:雙精度浮點數,依 IEEE 754 標準固定 64 位元。這一「長整數長度不固定、浮點數固定 64 位」的差異,直接導致 PHP 某些行為具備平台相關性。本文以下討論預設在 64 位元 long 環境下。
雙精度浮點數佔 64 位元:
這意味著:任何超過 253 - 1(即 9,007,199,254,740,991)的整數,轉為 double 再轉回 long 時,必然發生精度遺失。
PHP 在解析腳本字面量時,會自動判斷數值是否超出當前平台 long 範圍:
<?php
$a = 9223372036854775807; // 64 位元有號整數最大值
$b = 9223372036854775808; // 最大值 + 1
var_dump($a); // int(9223372036854775807)
var_dump($b); // float(9.22337203685E+18)
超出範圍即以 IS_DOUBLE 儲存,隨之而來的精度問題即刻顯現:
var_dump($a === ($b - 1)); // false
同樣的程式碼在 64 位元系統正常,移植到 32 位元系統可能因隱式轉型導致精度遺失而錯誤。PHP 提供 PHP_INT_MAX 常數供檢查臨界值,處理大整數運算時,強烈建議:
bcmath 或 gmp 擴展進行精確運算php.precisionphp.ini 中的 precision 參數控制浮點數輸出的有效位數,預設通常為 14。調整此值僅影響顯示,不影響內部儲存精度。
安全整數範圍: - (253 - 1) 到 253 - 1。在此範圍內進行 long → double → long 往返轉換,保證無精度損失。超出此範圍,請改用字串或高精度擴展庫處理。