我想知道为什么array_uintersect_assoc()
自定义比较功能:
如果第一个参数被认为分别小于、等于或大于第二个参数,则必须返回一个小于、等于或大于零的整数
当我比较两个数组时,我只需要一个布尔返回值:元素要么匹配,要么不匹配。
这种行为的真正原因是什么?
我想知道为什么array_uintersect_assoc()
自定义比较功能:
如果第一个参数被认为分别小于、等于或大于第二个参数,则必须返回一个小于、等于或大于零的整数
当我比较两个数组时,我只需要一个布尔返回值:元素要么匹配,要么不匹配。
这种行为的真正原因是什么?
该函数已以这种方式实现,以允许使用使用这种返回策略的“经典”比较函数。出于显而易见的原因,这样的函数通常需要能够表达布尔返回值无法实现的三种情况。
但是,您也可以使用返回布尔结果的比较函数,因为 php 作为弱类型语言会自动为您转换。看一下这个示例,它是函数文档中给出的示例的略微修改版本:
<?php
function mystrcasecmp($a, $b) {
return strcasecmp($a, $b) ? true : false;
}
$array1 = array("a" => "green", "b" => "brown", "c" => "blue", "red");
$array2 = array("a" => "GREEN", "B" => "brown", "yellow", "red");
print_r(array_uintersect_assoc($array1, $array2, "mystrcasecmp"));
您可以看到这里使用的比较函数返回一个布尔值,但结果完全相同。
底线:现有的实现更加灵活,同时允许使用返回布尔结果的比较函数。
我只需要布尔值:元素匹配或不匹配。
您需要反转将转换为 int 的布尔值,因为这些array_intersect
和array_diff
调用自定义函数的函数仅限定返回零结果的数据(即:、、、、、空字符串null
、空数组)。这是一个三元实现:false
"0"
0
array_uintersect_assoc($array1, $array2, fn($a, $b) => str_contains($a, $b) ? 0 : 1)
这个操作很容易混淆。当回调返回非数字字符串时,您的问题导致我使用 array_uintersect_assoc() 发布意外结果。
假设您要使用array_uintersect_assoc()
并且有以下两个输入数组:
$array1 = ["a" => "green", "b" => "brown", "c" => "blue", 0 => "red"];
$array2 = ["a" => "GREEN", "B" => "brown", 0 => "yellow", 1 => "red", "c" => "blue"];
现在假设您要进行一个返回布尔值的自定义函数调用。我将提名 PHP8 str_contains()
,这对于这个演示来说已经足够了。第一个数组将包含干草堆字符串,第二个数组将包含针字符串。
var_export(array_uintersect_assoc($array1, $array2, 'str_contains'));
这将检查第二个数组中第一个数组中的相同键然后在那些合格元素中,它将检查第二个数组的值是否在第一个数组的字符串中找到。作为一个“相交”调用,您会直观地期望:
['c' => 'blue']
因为只有c
第二个数组中的 -keyed 元素具有一个值,其中第二个数组的值区分大小写存在于第一个数组的值中。
但是,您实际得到的是:
['a' => 'green', 0 => 'red']
什么?!?您在结果中获得带有键的元素的原因是a
,在返回结果时,包含在其名称中的0
任何函数都会进行合格匹配。array_
diff/intersect
u
0
当c
元素的值被馈送到 时str_contain()
,返回一个true
布尔值。 array_uintersect_assoc()
然后强制将布尔值转换为 int 类型。将布尔值转换为整数时,false
变成0
和true
变成1
。
要修复此行为以获得预期结果,您不能简单地intersect
将函数名称中的单词更改为diff
-- 这会创建:
['b' => 'brown', 'c' => 'blue']
这是因为b
在第二个数组中没有相同的对应键。 c
确实有一个相同的对应键,true
结果 fromstr_contains()
被 评估为“不保留” array_udiff_assoc()
。
最后,解决方法是反转布尔值,使 a变为true
非零。(演示)0
false
var_export(
array_udiff_assoc(
$array1,
$array2,
fn($a, $b) => str_contains($a, $b) ? 0 : 1;
// or !str_contains($a, $b) until the day when PHP throws a DEPRECATED warning for returning a boolean
)
);