为什么 in_array() return 出乎意料/奇怪的结果?

Why does in_array() return unexpected / strange results?

为什么 in_array() 有时表现得如此奇怪并且 returns 出现如此意想不到的结果?

让我们看几个例子:

$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() 和第三个参数 strict true:

$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() 的工作方式可能与您预期的一样.

(参数strictphp.net documentation中也有描述。)

说明

在参数strict不设置为true的情况下,搜索值与数组的每个值之间的比较是相等的,而不是恒等的。这意味着值的类型无关紧要,因此 PHP 在内部将值转换为相同的数据类型以便能够比较它们。

这意味着在第一个示例中,搜索值 'Gary' 在与 true 进行比较时被转换为布尔值,因此结果是 truetrue,这显然是 true.

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

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

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

不幸的是,调用 in_array()strict 参数的默认值是......嗯,是的,false。 :-/ PHP 正在输入...

后果

在没有将 strict 参数设置为 true 的情况下,您真的永远不应该调用 in_array()。当您没有混合类型的数组并且您只检查具有相同类型的值时,in_array() 会按预期工作。看这个例子:

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

所以至少这是按预期工作的。但在我看来,总是用 strict true 调用 in_array() 要容易得多。 (类似于 "SQL Injection Problem"...只要始终使用 PDO 和准备好的语句,这样你就安全了,即使它是一个没有可变参数的查询。那么你总是安全的。)

不过要小心

你绝对应该用 strict 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 即可使用。 ;-)