127

我有以下代码:

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

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

也有可能将价格保留为 0,因为该项目是奖金,或者因为价格将在稍后设置。

但是,当价格没有设置时,它的初始值为 0,if上面指示的循环评估为真,价格设置为 -1。也就是说,它认为 0 等于“e”。

这怎么解释?

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

4

9 回答 9

135

您正在==为您整理类型。

0是一个 int,所以在这种情况下,它将转换'e'为一个 int。哪个不可解析为 one 并将成为0. 一个字符串'0e'会变成0并且会匹配!

利用===

来自PHP.net

使用 == 和其他非严格比较运算符在字符串和数字之间进行比较目前通过将字符串转换为数字,然后对整数或浮点数执行比较来工作。这导致了许多令人惊讶的比较结果,其中最值得注意的是 0 == "foobar" 返回 true。

然而这种行为在PHP 8.0中改变了:

当与数字字符串进行比较时,PHP 8 使用数字比较。否则,它将数字转换为字符串并使用字符串比较。

PHP 7

0 == 'foobar' // true
0 == '' // true
4 == '4e' // true (4e is cast as a number and becomes 4)

PHP 8 在进行比较之前将数字转换为字符串

0 == 'foobar' // false
0 == '' // false
4 == '4e' // false ('4e' is considered non-numeric therefore 4 is cast as a string and becomes '4')

这是一个重大变化,因此它是在一个新的主要 PHP 版本中实现的。此更改破坏了依赖于旧行为的脚本的向后兼容性。

于 2011-07-27T10:49:01.317 回答
48

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

如果将数字与字符串进行比较或比较涉及数字字符串,则每个字符串都将转换为数字并以数字方式执行比较。[...] 比较时不会发生类型转换,===因为!==这涉及比较类型和值。

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

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

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

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

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

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

于 2011-12-29T19:22:53.863 回答
24
"ABC" == 0

求值true,因为first "ABC"被转换为整数并变为0 then它与 比较0

这是 PHP 语言的一种奇怪行为:通常人们希望0被提升为字符串"0",然后与"ABC"结果进行比较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;
}
于 2018-02-21T17:59:18.060 回答
8

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

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'] 始终是整数,则永远不会真正实现。

于 2013-03-29T14:47:20.983 回答
8

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

'0' == 0 will be true

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

'0' === 0 will be false
于 2011-07-27T10:47:46.067 回答
6

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

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

它与这个用例并不完全相关,但考虑到相似性和事实,这是在询问验证(字符串)“0”为假的问题时搜索结果往往会发现,我认为这会对其他人有所帮助。

http://www.php.net/manual/en/filter.filters.validate.php

于 2012-04-26T05:54:06.233 回答
6

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

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

  • ===意思是“等于”,
  • ==意思是“eeeeh ..有点像”
于 2011-07-27T10:47:39.840 回答
4

基本上,始终使用===运算符,以保证类型安全。

在此处输入图像描述

在此处输入图像描述

于 2020-03-25T10:04:59.597 回答
2

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

// 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)
于 2019-02-15T11:31:52.693 回答