PHP字符串比较,为什么强制转换为float


php string comparison, why cast to float

我遇到过这段代码

<?php
$a = md5('240610708');
$b = md5('QNKCDZO');
echo "$a'n";
echo "$b'n";
echo "'n";
var_dump($a);
var_dump($b);
var_dump($a == $b); 

计算两个字符串,它们可能是一个数字0exxxxxx。我明白,如果在数字上下文中使用任何一个,那么字符串将被视为数字,如http://www.php.net/manual/en/language.types.string.php#language.types.string.conversion

所确认的那样

在数值上下文中计算字符串时,结果值为和类型确定如下:

如果字符串不包含任何字符'。', 'e'或'e'并且数值符合整数类型限制(由PHP_INT_MAX),则该字符串将被计算为整数。在其他方面在这种情况下,它将作为浮点数计算。

该值由字符串的初始部分给出。如果字符串从有效的数字数据开始,这将是所使用的值。否则,该值为0(零)。有效的数字数据是可选符号,后面跟着一个或多个数字(可选包含小数点),后跟一个可选的指数。指数是an'e'或'e'后面跟着一个或多个数字。

我只是不确定为什么==触发数值比较,当双方都是字符串类型。

TL;DR

这是PHP中字符串"智能"比较的结果。是的,这不是你所期望的,但现在-它是如何实现的。

<标题>挖掘更深层次的h1>

要了解其中的原因,您需要查看PHP源代码(无论好坏)。在PHP中,有compare_function这样的东西用于处理比较。它包含不同类型参数的不同情况。对于字符串,它是:

case TYPE_PAIR(IS_STRING, IS_STRING):
    zendi_smart_strcmp(result, op1, op2);
    return SUCCESS;

TYPE_PAIR和其他东西一样,只是一个宏。

进入更深的

从上一步,我们现在移动到zendi_smart_strcmp。比较两个字符串是PHP的"聪明之举"。

if ((ret1=is_numeric_string_ex(Z_STRVAL_P(s1), Z_STRLEN_P(s1), &lval1, &dval1, 0, &oflow1)) && (ret2=is_numeric_string_ex(Z_STRVAL_P(s2), Z_STRLEN_P(s2), &lval2, &dval2, 0, &oflow2))) 
{
    //compare as two numbers, I've omitted this
}
else 
{
    string_cmp: //yes, yes, we're using goto
    Z_LVAL_P(result) = zend_binary_zval_strcmp(s1, s2);
    ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(result)));
}

里省略了代码还有一部分确定结果是longdouble——但这是无关紧要的因为我们已经知道是什么导致了比较浮点数:只要字符串可视为数字,PHP将使用生产比较——和——是的,,目的是(是的,字符串"1000" = "1e3"当使用==运营商"255""0xFF"——他们不包含"e"(指数),但仍然是 = )

<标题> 解决方案

您可以使用以下语句来限制这种情况,例如:

var_dump("0e8" == "0e6"); //true

所以不需要处理md5哈希。如果将其作为数字进行比较,则为真(因为两个操作数都是有效的浮点数,并且0 x 10^8 == 0 x 10^6)。但是它们和字符串不一样。因此,您的直接解决方案将是-使用===运算符进行比较:

var_dump("0e8" === "0e6"); //false

是的,这在PHP中是一件令人困惑的事情——因为它不明显(至少是有争议的)。