php字符串比较,为什么要转换为float(php string comparison, why cast to float)

编程入门 行业动态 更新时间:2024-10-25 20:28:16
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);

这将评估2个字符串,可以是数字0exxxxxx 。 据我所知,如果在数字上下文中使用任何一个,那么该字符串将被视为一个数字,如http://www.php.net/manual/en/language.types.string.php#language.types所证实。 string.conversion

在数值上下文中计算字符串时,结果值和类型将按如下方式确定。

如果字符串不包含任何字符'。','e'或'E',并且数值适合整数类型限制(由PHP_INT_MAX定义),则字符串将被计算为整数。 在所有其他情况下,它将被评估为浮点数。

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

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

Ive come across this code

<?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);

This evaluates that 2 strings which could be a number 0exxxxxx. I understand that if either are used in a numeric context then the string will be taken as a number, as confirmed by http://www.php.net/manual/en/language.types.string.php#language.types.string.conversion

When a string is evaluated in a numeric context, the resulting value and type are determined as follows.

If the string does not contain any of the characters '.', 'e', or 'E' and the numeric value fits into integer type limits (as defined by PHP_INT_MAX), the string will be evaluated as an integer. In all other cases it will be evaluated as a float.

The value is given by the initial portion of the string. If the string starts with valid numeric data, this will be the value used. Otherwise, the value will be 0 (zero). Valid numeric data is an optional sign, followed by one or more digits (optionally containing a decimal point), followed by an optional exponent. The exponent is an 'e' or 'E' followed by one or more digits.

Im just not sure why == triggers a numeric comparison when both sides are of type string.

最满意答案

TL; DR

这是PHP中字符串“智能”比较的结果。 是的,这不是你所期望的,但就目前而言 - 它是如何实现的。

深层发掘

保持比较

为了实现这个原因,你需要研究PHP源代码(更好或更好)。 在PHP中,有比较函数用于处理比较。 它包含不同类型参数的不同情况。 所以,对于字符串,它是:

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))); }

在省略的代码中还有一部分用于确定结果是long还是double - 但这是无关紧要的,因为我们已经知道是什么导致比较为浮点数:只要字符串可以被视为数字,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中是一个令人困惑的事情 - 因为它并不明显(至少有争议)。 但这就是目前的工作方式。

TL;DR

This is the result of "smart" comparison for strings in PHP. Yes, it is not what you can expect, but for now - it is how it's implemented.

Digging deeper

Maintaining comparison

To realize reason for this, you'll need to look into PHP sources (for greater good or bad). In PHP, there is such thing as compare_function which is used to handle comparisons. It contains different cases for different types of arguments. So, for strings it is:

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

TYPE_PAIR, as any other stuff, is just a macro.

Moving deeper

From previous step, we're now moving to zendi_smart_strcmp. It is PHP's "smart thing" to compare two strings. And here we are:

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))); }

Inside omitted code there is also part for determining if result is long or double - but that's irrelevant since we've already know what caused comparison as floats: as long as strings can be treated as numbers, PHP will use that to produce comparison - and - yes, that is intended (so, yes, string "1000" is equal to "1e3" when using == operator, same for "255" and "0xFF" - they don't contain "e" (exponent) part, but still are equal)

Solution

You may restrict the case with, for example:

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

So no need to deal with md5 hashes. If compare that as numbers, it's true (since both operands are valid floats, and 0 x 10^8 == 0 x 10^6). But they are not same as strings. Thus, your direct solution would be - use === operator to compare:

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

Yes, it's a confusing thing in PHP - because it is not obvious (and debatable at least). But that's how it currently works.

更多推荐

本文发布于:2023-08-07 02:03:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1458416.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:字符串   转换为   php   float   cast

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!