回调 returns 非数字字符串时 array_uintersect_assoc() 出现意外结果

Unexpected results with array_uintersect_assoc() when callback returns non-numeric string

我正在调用 array_uintersect_assoc() 并使用回调函数 strpbrk() 来演示关于 return 值如何根据类型进行评估的要点。

给定干草堆的关联数组,例如:

[
    'one' => '0',
    'two' => '1',
    'three' => '0',
    'four' => '1',
    'five' => 'a',
    'six' => 'b',
    'seven' => 'a',
    'eight' => 'b'
]

还有一个关联的针数组,例如:

[
    'one' => '1',
    'two' => '0',
    'three' => '0',
    'four' => '1',
    'five' => 'a',
    'six' => 'b',
    'seven' => 'a'
    'eight' => 'b',
]

代码:

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

输出:

['four' => '1']

因为 returned 字符串值 ab 是真实的,为什么结果中不包含具有键 seveneight 的元素?

相关 array_uintersect_assoc() 页面未专门解决此问题:

PHP Manual 声明 return 值将被评估为 int 类型值而不是布尔类型值。

callback(mixed $a, mixed $b): int

此本机函数旨在从 three-way 比较中获取 return 值。这意味着 return 零值的元素被保留,其他所有元素都被删除。

在比较 seven 键控值时,(strpbrk('a', 'a')) returned 值是字符串值 a。 (以下解释将适用于 eight 键值的比较。)虽然 a 被认为是“真实的”是正确的,因为当它被转换为布尔值时,它变成 true。将布尔值 true 转换为 int 值时将变为 1 也是正确的。但是,当 a 直接转换为 int 值时,它变成 0 —— 这就是 array_unintersect_assoc() 评估回调的 return 值的方式,这也解释了为什么元素 seveneight 不保留在结果数组中。 (Comprehensive demo of this task and the below snippet)

var_export([
    // haystack, then needle
    '0:1' => strpbrk('0', '1'), // false
    '1:0' => strpbrk('1', '0'), // false
    '0:0' => strpbrk('0', '0'), // '0'
    '1:1' => strpbrk('1', '1'), // '1'
    'a:b' => strpbrk('a', 'b'), // false
    'b:a' => strpbrk('b', 'a'), // false
    'a:a' => strpbrk('a', 'a'), // 'a'
    'b:b' => strpbrk('b', 'b'), // 'b'
    'a as bool' => (bool)'a', // true
    'a as int' => (int)'a', // 0
    'a as bool then int' => (int)(bool)'a', // 1
]);

因为很多演示 array_uintersect_assoc() 的片段(包括手册)都使用 strcasecmp() 作为回调,我将提供一些其他回调以向研究人员提供更多上下文。

归根结底,还是不够理解how different variable types are juggled to booleans. It is imperative that developers understand how different value types convert to ints

保留 return 零整数的值有点 awkward/conterintuitive -- 因为零是一个错误的值。对于使用 str_contains()str_starts_with()str_ends_with() 等 return 布尔结果的任何人,您需要将本机函数从 uintersect 反转为 udiff 以便正确处理 true 布尔值 return。

strcmp()

代码:(Breakdown Demo)

var_export(
    array_uintersect_assoc([
        ['one' => 'a', 'two' => 'aa', 'three' => 'a', 'four' => 'aa'], // string1s
        ['one' => 'aa', 'two' => 'a', 'three' => 'a', 'four' => 'aa'], // string2s
        'strcmp'
    ])
);
// ['three' => 'a', 'four' => 'aa']

trim()

代码:(Breakdown Demo)

var_export(
    array_uintersect_assoc([
        ['one' => 'a', 'two' => 'ab', 'three' => '0', 'four' => '1'], // strings
        ['one' => 'ab', 'two' => 'a', 'three' => '1', 'four' => '0'], // masks
        'trim'
    ])
);
// ['one' => 'a', 'two' => 'ab', 'three' => '0']

strcspn()

代码:(Breakdown Demo)

var_export(
    array_uintersect_assoc([
        ['one' => 'a', 'two' => 'ba', 'three' => 'a', 'four' => 'ba'], // strings
        ['one' => 'ba', 'two' => 'a', 'three' => 'a', 'four' => 'ba'], // masks
        'strcspn'
    ])
);
// ['one' => 'a', 'three' => 'a', 'four' => 'ba']

str_repeat()

代码:(Breakdown Demo)

var_export(
    array_uintersect_assoc([
        ['one' => 0, 'two' => 1, 'three' => 0, 'four' => 1], // strings
        ['one' => 1, 'two' => 0, 'three' => 0, 'four' => 1], // times
        'str_repeat'
    ])
);
// ['one' => 0, 'two' => 1, 'three' => 0]

str_contains()

代码:(Breakdown Demo)

var_export(
    array_uintersect_assoc([
        ['one' => 'a', 'two' => 'aa', 'three' => 'a', 'four' => 'aa'], // haystacks
        ['one' => 'aa', 'two' => 'a', 'three' => 'a', 'four' => 'aa'], // needles
        'str_contains'
    ])
);
// ['one' => 'a']