为什么in_array()会返回意外/奇怪的结果


Why does in_array() return unexpected / strange results?

为什么in_array()有时表现得如此奇怪,并返回如此意外的结果?

让我们看看几个例子:

$arrayWithTrue = ['Andreas', 'Philipp', true];
$arrayWithNull = [1, 2, 3, null];
$arrayWithMinusOne = [-1];
var_dump(in_array('Gary', $arrayWithTrue)); // returns bool(true)
var_dump(in_array(0, $arrayWithNull)); // returns bool(true)
var_dump(in_array(true, $arrayWithMinusOne)); // returns bool(true)

嗯?这里发生了什么!?

(几年前,起初我想知道这种奇怪的行为。不过,我认为这可能对一些人有用,所以我提出了这个问题。)

解决方案(简而言之):

始终使用in_array()和第三个参数stricttrue:

$arrayWithTrue = ['Andreas', 'Philipp', true];
$arrayWithNull = [1, 2, 3, null];
$arrayWithMinusOne = [-1];
var_dump(in_array('Gary', $arrayWithTrue, true)); // returns bool(false)
var_dump(in_array(0, $arrayWithNull, true)); // returns bool(false)
var_dump(in_array(true, [-1], true)); // returns bool(false)

因此,当您使用in_array()true作为第三个参数时,搜索值和数组之间的比较是严格的,这意味着in_array()的工作方式与您可能预期的一样。

(php.net文档中也描述了参数strict。)

解释

如果不将参数strict设置为true,则搜索值和数组的每个值之间的比较是通过等式而不是通过恒等式进行的。这意味着值的类型无关紧要,因此PHP在内部将值转换为相同的数据类型,以便能够对它们进行比较。

这意味着在第一个例子中,当搜索值'Gary'true进行比较时,它被转换为布尔值,因此它导致truetrue的比较,这显然是true

第二个数组也是如此,其中0最终与null进行比较,得到true,尽管0显然与null不同(当您处理数字和/或函数结果时,这可能特别棘手,例如,null可以表示空值,而不是0)。

第三个数组看起来非常奇怪,因为我们检查数组中的值true,它只包含-1,但in_array()仍然返回true进行比较。在这种情况下,-1被转换为布尔true。因此,问题在两个方向上都是一样的。

您可以在这个Stack Overflow答案中找到更多关于PHP中比较问题的示例(因为这与==/===相同)。

不幸的是,调用in_array()strict参数的默认值是…嗯,是的,false。://PHP和它正在键入。。。

后果

如果不将strict参数设置为true,则永远不应该调用in_array()。如果没有混合类型的数组,并且只检查具有相同类型的值,则in_array()会按预期工作。参见此示例:

$arrayWithStrings = ['Andreas', 'Philipp', 'Friedrich'];
var_dump(in_array('Gary', $arrayWithStrings)); // returns bool(false)

所以,至少这是意料之中的事。但在我看来,总是用stricttrue调用in_array()要容易得多。(类似于"SQL注入问题"……只要始终使用PDO和准备好的语句,即使这是一个没有可变参数的查询,也会很安全。这样你就永远安全了。)

不过要小心

您绝对应该使用严格true来调用in_array()。但有一个缺点,我想提一提(尽管这是显而易见的)。在调用in_array()时,必须使用正确的类型,然后:

$arrayWithNumbers = [1, 2, 3];
var_dump(in_array('1', $arrayWithNumbers, true)); // returns bool(false)

但当你知道你比较数字时,你可以只使用类型铸造:

$arrayWithNumbers = [1, 2, 3];
var_dump(in_array((int)'1', $arrayWithNumbers, true)); // returns bool(true)

奖金

// Comparing false with an empty array
var_dump(in_array(false, [[]])); // returns bool(true)

嗯,是的。。。只需将strict设置为true.;-)