背景
某个仓促上线项目的复杂查询使用到了in_array和使用数组的key进行判断是否在数组里,导致某些结果不符合预期。
数组key的强制转换的例子
<?php
$arr = [
'0' => '0',
'1-3' => '1-3',
'20-30' => '20-30',
'30-50' => '30-50',
'>50' => '大于50',
];
echo "<pre>";
foreach ($arr as $k => $v) {
var_dump($k);
}
echo "</pre>";
输出结果:
int(0)
string(3) "1-3"
string(5) "20-30"
string(5) "30-50"
string(3) ">50"
1.查了一下官方文档,在PHP官方文档中给出的Key值转换说明如下:
- 包含有合法整型值的字符串会被转换为整型。例如键名 “8” 实际会被储存为 8。但是 “08” 则不会强制转换,因为其不是一个合法的十进制数值。
- 浮点数也会被转换为整型,意味着其小数部分会被舍去。例如键名 8.7 实际会被储存为 8。
- 布尔值也会被转换成整型。即键名 true 实际会被储存为 1 而键名 false 会被储存为 0。
- Null 会被转换为空字符串,即键名 null 实际会被储存为 “”。
- 数组和对象不能被用为键名。坚持这么做会导致警告:Illegal offset type。
2.很明显key为 ‘0’ 的是一个合法整型值的字符串,所以它被强制转换为整型,
非严格模式的in_array的例子
<?php
$arr = [
'0' => '0',
'1-3' => '1-3',
'20-30' => '20-30',
'30-50' => '30-50',
'>50' => '大于50',
];
$in_array_arr = [
'1-3',
'20-30',
'>50'
];
echo "<pre>";
foreach ($arr as $k => $v) {
if (in_array($k, $in_array_arr)) {
echo $k .' 存在数组中' . nl2br(PHP_EOL);
}
}
echo "</pre>";
输出结果:
0 存在数组中
1-3 存在数组中
20-30 存在数组中
>50 存在数组中
因为in_array非严格模式下是不判断数据类型是否一样的,’>50’ 跟 0 相比较是相等的。
严格模式in_array的例子
既然非严格模式的不行,那使用严格模式的呢?
<?php
$arr = [
'0' => '0',
'1-3' => '1-3',
'20-30' => '20-30',
'30-50' => '30-50',
'>50' => '大于50',
];
$in_array_arr = [
'0',
'1-3',
'20-30',
'>50'
];
echo "<pre>";
foreach ($arr as $k => $v) {
if (in_array($k, $in_array_arr, true)) {
echo $k .' 存在数组中' . nl2br(PHP_EOL);
}
}
echo "</pre>";
输出结果:
1-3 存在数组中
20-30 存在数组中
>50 存在数组中
查看上面数组key的强制转换的知识点可知key为 ‘0’ 的会强制转换成整型的 0,这里使用了严格模式,所以也判断类型是否相同
解决方法
<?php
$arr = [
'0' => '0',
'1-3' => '1-3',
'20-30' => '20-30',
'30-50' => '30-50',
'>50' => '大于50',
];
$in_array_arr = [
'0',
'1-3',
'20-30',
'>50'
];
echo "<pre>";
foreach ($arr as $k => $v) {
if (in_array((string)$k, $in_array_arr, true)) {
echo $k .' 存在数组中' . nl2br(PHP_EOL);
}
}
echo "</pre>";
输出结果
0 存在数组中
1-3 存在数组中
20-30 存在数组中
>50 存在数组中
把它强转字符串类型再使用in_array判断是否在数组里
结论
- 数组key有强制转换的问题需要注意;
- in_array尽量使用严格模式;
- 使用in_array需要注意是否也要判断数据类型。如果是混合类型的话,都统一强转为同一数据类型再使用in_array判断是否在数组里
额外知识点
- in_array是线性查找,时间复杂度为O(n),所以数据量也大,性能就越差;
- 建议使用isset或array_key_exists,它们的时间复杂度为O(1)
参考链接
https://www.php.net/manual/zh/language.types.array.php
https://www.php.net/manual/zh/function.in-array.php