为什么PHP认为0等于字符串?


111

我有以下代码:

$item['price'] = 0;
/* Code to get item information goes in here */
if($item['price'] == 'e') {
    $item['price'] = -1;
}

旨在将商品价格初始化为0,然后获取有关其的信息。如果价格被告知为“ e”,则表示交换而不是卖出,其以负数存储在数据库中。

也有可能将价格保留为0,这是因为该项目是奖励商品,或者是因为价格将在以后设置。

但是,每当未设置价格时,其初始值将为0,则上述if循环将评估为true,并将价格设置为-1。也就是说,它认为0等于“ e”。

如何解释呢?

当价格提供为0(初始化后)时,该行为是不稳定的:有时if评估为true,有时评估为false。*


1
我发现使用三重===而不是双==可以得到预期的行为。但这仍然很奇怪。
塞尔吉奥Domingues

2
(参考)充分地章PHP手册中所说明的类型杂耍以及在示出的类型的比较表
戈登

1
如果唯一可能的字符串类型是'e',您是否只能进行is_string($ item [“ price”])检查?这将比===更有效。[需要引用]
Jimmie Lin

在字符串和整数之间的弱比较中,字符串将转换为整数(而不是将整数“提升”为字符串)。if((string)$item['price'] == 'e')解决奇怪的行为。见stackoverflow.com/a/48912540/1579327对于更多的细节
圣保罗

请注意以下@Paolo注释中的另一种情况,其中使用double equals运算符时0(整数)等于任何其他字符串。
Haitham Sweilem

Answers:


113

您正在做的工作==将为您整理类型。

0是一个int,因此在这种情况下它将转换'e'为一个int。这是不可解析的,并将成为事实0。一个字符串'0e'将成为0并将匹配!

===


14
比较松散的另一个缺点。
MC Emperor

5
整rick。刚碰到这一步,惊讶于为什么string ==0。一定要记住这一点。
Grzegorz

2
当我循环使用字符串键时,我也在这个头上挠头,但是该数组有一个初始的“零”索引项,该索引项在第一个字符串键比较中一直保持为true。我当时是什么样?怎么样……所以,果然,这个答案使事情变得清晰起来!我很惊讶,整个问题还没有一个被接受的答案。只是显示一些提问者是混蛋。
IncredibleHat

48

这是由于PHP如何执行比较运算符所表示的==比较运算

如果将数字与字符串进行比较,或者比较涉及数字字符串,则每个字符串都将转换为数字,并且比较将以数字方式进行。[…]当比较是===!==因为涉及类型和值的比较时,不会进行类型转换。

由于第一个操作数是数字(0),第二个操作数是字符串('e'),因此该字符串也将转换为数字(另请参见与各种类型比较)。关于字符串数据类型的手册页定义了如何完成字符串到数字的转换

在数字上下文中评估字符串时,结果值和类型的确定如下。

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

在这种情况下,字符串为'e',因此它将被评估为浮点型:

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

由于'e'不是以有效的数字数据开头,因此其计算结果为float 0


3
php将大多数内容设计为易于比较,然后抛出一些陷阱来破坏我们的一天。这与PHP的其余设计哲学不符。除非欺骗存在哲学???
user3338098 2015年

1
特别是因为“ e”强制转换为真,而“”强制转换为假
user3338098

20
"ABC" == 0

进行评估,true因为首先 "ABC"将其转换为整数,0 然后将其与进行比较0

这是PHP语言的一种奇怪行为:通常,人们期望0将其提升为字符串"0",然后与"ABC"result 进行比较false。也许这就是其他语言(如JavaScript)在弱比较"ABC" == 0评估中所发生的情况false

进行严格的比较可以解决问题:

"ABC" === 0

评价false

但是,如果我确实需要将数字作为字符串与数字进行比较该怎么办?

"123" === 123

进行评估,false因为左项和右项的类型不同。

实际需要的是进行弱比较,而不会遇到PHP类型变戏法的陷阱。

解决方案是显式地将术语扩展为字符串,然后进行比较(严格或弱不再重要)。

(string)"123" === (string)123

true

(string)"123" === (string)0

false


应用于原始代码:

$item['price'] = 0;
/*code to get item information goes in here*/
if((string)$item['price'] == 'e') {
    $item['price'] = -1;
}

9

==运算符将尝试匹配值,即使它们的类型不同。例如:

'0' == 0 will be true

如果还需要类型比较,请使用===运算符:

'0' === 0 will be false

9

您的问题是双等号运算符,该运算符会将右侧的成员转换为左侧的类型。如果您愿意,请使用严格。

if($item['price'] == 'e') {
    $item['price'] = -1;
}

让我们回到上面复制的代码。在这种情况下,大多数情况下,$ item ['price']是一个整数(显然,它等于e时除外)。因此,根据PHP的法律,PHP将类型转换"e"为整数,从而产生int(0)。(不相信我吗?<?php $i="e"; echo (int)$i; ?>)。

为了轻松摆脱这种情况,请使用三元均等(精确比较)运算符,该运算符将检查类型并且不会隐式地进行类型转换。

PS:一个PHP有趣的事实:a == b并不意味着b == a。举个例子并扭转它:if ("e" == $item['price'])只要$ item ['price']始终是整数,就永远不会真正实现。


7

PHP中有一种相当方便的方法来验证“ =”和“ 0”,“ false”,“ off”和== true的混合,“ 1”,“ on”,“ true” == true,这通常被忽略。这对于解析GET / POST参数特别有用:

filter_var( $item['price'], FILTER_VALIDATE_BOOLEAN );

这与该用例无关紧要,但是鉴于相似性和事实,这是在询问验证(字符串)“ 0”的问题时往往会发现结果搜索为假,我认为这会帮助他人。

http://www.php.net/manual/zh-CN/filter.filters.validate.php


6

您应使用===代替==,因为普通运算符不会比较类型。相反,它将尝试对项目进行类型转换。

同时===考虑项目的类型。

  • === 表示“等于”,
  • == 意思是“ eeeeh ..有点像”

1
我懂了。现在可以正常工作(使用广播):if((string)$item['price']=='e'){ $item['price'] = -1; }
SérgioDomingues

但您不应该那样做。只是使用的===运营商
tereško

3

我认为最好以我做过的例子来展示,同时遇到同样奇怪的行为。查看我的测试用例,希望它可以帮助您更好地理解行为:

// Normal comparison using the == Operator
echo (0 == "0"); // true
echo (0 == "a"); // true
echo (0 == "safta!"); // true
echo (1000 == "bla"); // false. It appears that PHP has a weird behavior only with the number / string 0 / "0" according to the past 3 examples.
echo (23 == "23"); // true. So as we said, PHP has a problem (not a problem but weird behavior) only when the number / string 0 (or "0") is present
echo (23 == "24"); // false. values aren't equal (unlike last example). The type is less relevant with the == operator as we can see.

// Now using the === and !== Operators
echo ("0" === 0); // false, since === requires both value and type to be the same. Here, type is different (int vs string)
echo ("0" !== 0); // true because they aren't the same in terms of === comparison (type is different and that's why it's true)
echo ("bla" === "blaa"); // false because the values are not the same. The type is the same, but === checks for both equal type and equal value.

//Now using casting and === Operator:
echo ((string)123 === "123"); // true. The casting of the int 123 to string changed it to "123" and now both variables have same value and are of same type
echo ((int)"123" === 123); // true. The casting of the string 123 to int, changed it to int, and now both variables are of same value and type (which is exactly what the === operator is looking for)

// Now using casting and == Operator. Basically, as we've seen above, the == care less for the
// type of var, but more to the value. So the casting is less relevant here, because even
// without casting, like we saw earlier, we can still compare string to int with the == operator
// and if their value is same, we'll get true. Either way, we will show that:
echo ((string)123 == "123"); // true. The casting of the int 123 to string changed it to "123" and now both vars have same value and are of same type
echo ((int)"123" == 123); // true. The casting of the string 123 to int, changed it to int, and now both vars are of same value and type (which is exactly what the === operator is looking for)

很棒的测试,我做了同样的事情,但是从中得到了一张不错的桌子。看到我的答案
IAMTHEBEST

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.