任何人都可以解释为什么NAN和一个变量等于NAN根据 PHP 的版本而表现不同?
考虑以下代码:
$nan = NAN;
print "PHP Version: " . phpversion(). "\n" .
'0 < NAN ? ' . ( 0 < NAN ? 'TRUE' : 'FALSE' ) . "\n" .
'0 > NAN ? ' . ( 0 > NAN ? 'TRUE' : 'FALSE' ) . "\n" .
'0 == NAN ? ' . ( 0 == NAN ? 'TRUE' : 'FALSE' ) . "\n" .
'0 < $nan ? ' . ( 0 < $nan ? 'TRUE' : 'FALSE' ) . "\n" .
'0 > $nan ? ' . ( 0 > $nan ? 'TRUE' : 'FALSE' ) . "\n" .
'0 == $nan ? ' . ( 0 == $nan ? 'TRUE' : 'FALSE' ) . "\n" .
'is_nan(NAN) ' . ( is_nan(NAN) ? 'TRUE' : 'FALSE' ) . "\n" .
'is_nan($nan) ' . ( is_nan($nan) ? 'TRUE' : 'FALSE' ) . "\n" .
'gettype(NAN) is ' . gettype(NAN) . "\n" .
'gettype($nan) is ' . gettype($nan) . "\n";
Run Code Online (Sandbox Code Playgroud)
现在,如果我针对许多版本的 PHP(使用 MAMP)运行此代码,结果如下:
PHP Version: 5.3.5
0 < NAN ? TRUE
0 > NAN ? TRUE
0 == NAN ? FALSE
0 < $nan ? TRUE
0 > $nan ? TRUE
0 == $nan ? FALSE
is_nan(NAN) TRUE
is_nan($nan) TRUE
gettype(NAN) is double
gettype($nan) is double
PHP Version: 5.6.30 (and 5.5.30, 5.4.45)
0 < NAN ? FALSE
0 > NAN ? FALSE
0 == NAN ? FALSE
0 < $nan ? FALSE
0 > $nan ? FALSE
0 == $nan ? FALSE
is_nan(NAN) TRUE
is_nan($nan) TRUE
gettype(NAN) is double
gettype($nan) is double
PHP Version: 7.1.1 (and 7.0.15)
0 < NAN ? TRUE
0 > NAN ? TRUE
0 == NAN ? FALSE
0 < $nan ? FALSE
0 > $nan ? FALSE
0 == $nan ? FALSE
is_nan(NAN) TRUE
is_nan($nan) TRUE
gettype(NAN) is double
gettype($nan) is double
Run Code Online (Sandbox Code Playgroud)
PHP 中的函数可以依赖于与 NAN 的比较还是应该 NAN 只与 一起使用is_nan()?
此错误现已通过此提交修复。下面的解释说明了造成这种情况的原因。
关于你的第一个问题,似乎从 PHP7 开始,你会得到不同的结果,具体取决于表达式是在编译期间还是在运行时评估。
首先,值得注意的是,根据 IEEE754,其中一个元素是NAN, 的所有比较都应该返回false。您可以在此答案中找到一些详细信息。考虑到这一点,5.6 的行为似乎是正确的。
因此,对于运行时评估()的情况,该比较是通过以下代码0 < $nan在VM中完成的:
result = ((double)Z_LVAL_P(op1) < Z_DVAL_P(op2));
Run Code Online (Sandbox Code Playgroud)
该操作将分配 0,result最终返回。这将为我们提供 的预期输出FALSE。
在编译时评估()的情况下0 < NAN,比较是在编译期间通过以下代码完成的:
case TYPE_PAIR(IS_LONG, IS_DOUBLE):
Z_DVAL_P(result) = (double)Z_LVAL_P(op1) - Z_DVAL_P(op2);
ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
return SUCCESS;
Run Code Online (Sandbox Code Playgroud)
这里还发生了一些其他事情,该值的减法结果0 - NAN = NAN然后通过ZEND_NORMALIZE_BOOL宏,如下所示:
#define ZEND_NORMALIZE_BOOL(n) \
((n) ? (((n)>0) ? 1 : -1) : 0)
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,如果(n) > 0是false(这是 的情况NAN),宏将返回-1。然后将该值传递到您将找到的is_smaller_function位置:
ZVAL_BOOL(result, (Z_LVAL_P(result) < 0));
Run Code Online (Sandbox Code Playgroud)
鉴于此时result成立-1,这将被评估为TRUE。
关于你的第二个问题,我建议你永远不要依赖与的比较NAN并坚持使用is_nan(). 请注意,even 的NAN == NAN计算结果为false。