返回

PHP in_array() 常见误用与正确用法详解

php

PHP中 in_array() 的常见误用及正确用法

许多开发者在使用 PHP 函数 in_array() 时,会遇到一些看似不解的问题。 尤其是在处理 URL 参数,或者其他需要检查变量是否存在并处于某个预期值集合的场景时,误用尤其常见。本文将深入探讨 in_array() 的常见错误使用方式,以及相应的解决策略。

混淆 array_key_exists() 与 in_array() 的用法

常见的一个误区,是认为 in_array() 可以检查数组键(key)是否存在。实际上,in_array() 用于检测特定值是否出现在一个数组的值(value)中, 而不是检查键的存在。 当你尝试检查一个 URL 参数是否传递了有效的值时,如果你使用 in_array 就会出现错误。

错误示例:

以下代码尝试判断URL参数 id 是否为1,2,3 这三个值中的一个, 但实际情况是有可能 $_GET["id"] 这个键根本就不存在,从而产生notice 警告。

<?php
$allowed_ids = [1, 2, 3];

if(in_array($_GET['id'], $allowed_ids)) {
  echo "ID is valid!";
} else {
   echo "ID is invalid!";
}
?>

错误之处:
上述代码直接使用了$_GET['id'], 而没有预先判断 id 这个键是否存在。如果 id 键不存在, 则 PHP会抛出一个 "Undefined index" 错误。
另外一个错误是,直接使用 in_array in_array($_GET['id'], $allowed_ids) ,如果$_GET['id']不存在的话, 将导致第一个参数变成null ,从而 in_array() 将执行类型松散比较, 有可能将 null 和 0进行比较 ,这常常导致错误的结果。

正确方案:使用 isset() 结合 in_array()

正确的做法是,首先使用 isset()array_key_exists() 判断键是否存在,然后进行 in_array() 判断。isset() 检测变量是否已设置, 而且不是 NULL 。array_key_exists()则检查给定的键名或索引是否存在于数组中。

<?php
$allowed_ids = [1, 2, 3];

if (isset($_GET['id']) && in_array($_GET['id'], $allowed_ids, true)) {
    echo "ID is valid!";
} else {
    echo "ID is invalid!";
}
?>

操作步骤:

  1. 在一个php 文件中,加入以上代码片段
  2. 使用浏览器访问改文件 例如 your_file.php?id=2 ,你将看到 "ID is valid!"
  3. 如果使用 your_file.php?id=4 或者直接访问your_file.php, 将看到 "ID is invalid!"。

添加第三个参数true, 将启动in_array() 的严格类型检查, 这将防止类似 "2"2 被误判为相等的情况。 这对于确保类型的匹配是非常重要的,尤其在处理数字字符串时。

** 安全建议**
即使验证了一个请求参数存在,并属于预期的值, 对这个参数做进一步的过滤仍然是很必要的。 防止类似SQL 注入或跨站点脚本攻击(XSS)。 使用filter_varhtmlspecialchars() 这类函数进行过滤是必要的。

严格类型检查的疏忽

in_array() 默认使用非严格的比较 ( loose comparison ). 这意味着 "2" 将等于数字 2。 这种默认的行为有时会导致难以发现的bug。 当数组中的元素类型非常明确时, 开启严格模式(strict mode) 非常必要。

示例:使用严格模式进行比较

<?php
$allowed_ids = [1, "2", 3];
var_dump(in_array(2, $allowed_ids));       // Output: bool(true)  , 使用了非严格比较, "2"和2视为相等
var_dump(in_array(2, $allowed_ids, true)); // Output: bool(false) ,使用了严格模式比较 2不等于"2"

var_dump(in_array("2", $allowed_ids));     // Output: bool(true)
var_dump(in_array("2", $allowed_ids, true));// Output: bool(true)
?>

正如你看到的,in_array()的第三个参数设置为 true 后,其比较过程严格根据数据类型执行。
操作步骤:

  1. 将上述代码保存到php 文件。
  2. 在命令行中执行,比如 php your_file.php
  3. 分析打印输出,比较严格模式和非严格模式的区别

在实际应用中,当需要严格比较,请将in_array() 的第三个参数设为 true 。 避免类型转换带来的安全风险和业务逻辑问题。

其他注意事项

除了上述的核心误区,在使用 in_array() 时,还需要注意以下几点:

  • 当要检索的数组数据量巨大时, 使用in_array()效率并不高。 此时可以考虑用array_flip()函数将待检索的数组变成key=>value 形式, 并通过判断新数组中是否存在某个key 来判断该值是否存在于原始的数组中。 对于键值的检索,会明显加快检索的速度。
  • 确保待比较的数据类型,是与数组内存储的数据类型一致,以避免出现预料之外的逻辑。

总之, in_array() 函数看似简单, 但是深入理解其使用方式和潜在的坑非常必要。 正确地理解并运用这个函数,结合有效的输入校验, 能够编写出更加健壮和安全的 PHP 应用。