为什么 array_uintersect_assoc() 需要比较函数到 return 非布尔值?

Why does array_uintersect_assoc() need the comparison function to return non-boolean values?

我想知道为什么array_uintersect_assoc()的自定义比较功能:

must return an integer less than, equal to, or greater than zero if the first argument is considered to be respectively less than, equal to, or greater than the second

当我比较两个数组时,我只需要一个布尔值 return:元素匹配或不匹配。

这种行为的真正原因是什么?

该函数以这种方式实现,以允许使用使用此类 return 策略的 "classical" 比较函数。由于显而易见的原因,这样的函数通常需要能够表达 三种 情况,这对于布尔值 return 是不可能的。

但是,您也可以使用一个比较函数,它 return 一个布尔结果,因为 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"));

可以看到这里使用的比较函数return是一个布尔值,但是结果是完全一样的。

底线:现有的实现更加灵活,同时也允许使用比较函数 returning 布尔结果。

I only need boolean value: the elements either match or they dont.

TL;DR

您需要反转将转换为 int 的布尔值,因为这些调用自定义函数的 array_intersectarray_diff 函数仅限定 returns a [=83] 的数据=] 结果(即:nullfalse"0"0、空字符串、空数组)。这是一个三元实现:

array_uintersect_assoc($array1, $array2, fn($a, $b) => str_contains($a, $b) ? 0 : 1)

解释...

这个操作很容易混淆。你的问题让我想到 post .

假设您想使用 array_uintersect_assoc() 并且您有这两个输入数组:

$array1 = ["a" => "green", "b" => "brown", "c" => "blue", 0 => "red"];
$array2 = ["a" => "GREEN", "B" => "brown", 0 => "yellow", 1 => "red", "c" => "blue"];

现在假设您要进行自定义函数调用,returns 一个布尔值。我将提名 PHP8 的 str_contains(),这对于本次演示来说已经足够了。第一个数组将包含干草堆字符串,第二个数组将包含针字符串。

var_export(array_uintersect_assoc($array1, $array2, 'str_contains'));

这将在第二个数组中检查第一个数组中的相同键然后在那些符合条件的元素中,它将检查第二个数组的值是否在第一个数组的字符串中找到。作为“相交”调用,您会直观地期望:

['c' => 'blue']

因为只有第二个数组中的 c 键控元素有一个值,其中第二个数组的值 case-sensitively 存在于第一个数组的值中。

然而,你实际得到的是:

['a' => 'green', 0 => 'red']

什么?!?您在结果中获得带有键 a0 的元素的原因是因为名称中包含 u 的任何 array_ diff/intersect 函数正在返回 0 结果时的资格赛。

c 元素的值被馈送到 str_contain() 时,返回 true 布尔值。 array_uintersect_assoc() 然后强制将布尔值转换为 int 类型。将布尔值转换为整数时,false 变为 0 并且 true 变为 1.

要修复此行为以获得预期结果,您不能简单地将函数名称中的 intersect 单词更改为 diff -- 这会创建:

 ['b' => 'brown', 'c' => 'blue']

这是因为b在第二个数组中没有相同的对应键。 c 确实有一个相同的对应键,str_contains()true 结果被 array_udiff_assoc() 评估为“不保留”。

最后,解决方法是反转布尔值,使 true 变为 0false 变为 non-zero。 (Demo)

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
    )
);