hnwの日記

PHP 5.4.4から==の挙動が一段と難しくなりました


PHP==PHP==使PHP

==PHP 5.4.4稿

Bug #54547 の騒動




2Hacker News2^63PHPPHP'9223372036854775807' == '9223372036854775808'truePHPDIS

PHP====

PHPPHP :: Bug #54547 :: wrong equality of string numbersPHP 5.4.4

PHP 5.4.4での変更内容


PHP 5.4.4'9223372036854775807' == '9223372036854775808'false

./UPGRADING


Long numeric strings that do not fit in integer or double (such as
"92233720368547758070") are compared using string comparison if
they could otherwise result in precision loss - since 5.4.4.
 




"92233720368547758070"
使PHP5.4.4
 

PHP 5.4.3PHP 5.4.4

64bitPHP 5.5.11
<?php
$x1 = "9223372036854775807";
$y1 = "0X7FFFFFFFFFFFFFFF";
var_dump($x1==$y1); // bool(true), 数値比較している(文字列比較していたらfalseのはず)

$x2 = "9223372036854775808";
$y2 = "0X8000000000000000";
var_dump($x2==$y2); // bool(false), 文字列比較している(数値比較していたらtrueのはず, PHP 5.4.3以前ではtrue)

$x1,$y1PHP 5.4.3

$x2$y2PHP 5.4.3PHP 5.4.4

-2^63-12^6364bit-2^532^5332bit

仕様変更での考え漏れ




PHP64bit10^19010^19

Zend/zend_operators.czendi_smart_strcmp()Zend/zend_operators.his_numeric_string_ex()


<?php
$x3 = "9999999999999999999.0";
$y3 = "9999999999999999999.1";
var_dump($x3==$y3); // bool(true), 数値比較している(文字列比較していたらfalseのはず)

$x4 = "10000000000000000000.0";
$y4 = "10000000000000000000.00";
var_dump($x4==$y4); // bool(false), 文字列比較している(数値比較していたらtrueのはず, PHP 5.4.3以前ではtrue)

$x3$y3$x4$y410

まとめ

  • PHPで==を使って数値文字列同士を比較する場合、原則として数値比較されます
  • PHP5.4.4以降では、比較する数値文字列同士が大きくて両者が近すぎる場合には文字列比較になりました
    • 整数であれば-2^63-1以下または2^63以上(64bit環境)の場合
    • 浮動小数点数であれば-10^19以下または10^19以上(64bit環境)の場合
  • 比較演算子も影響を受けるので、ソート処理などにも注意が必要です

22