为什么array_diff_uassoc会比较值不匹配的键


Why does array_diff_uassoc compares keys whose value do not match

我刚刚读到关于奇怪php行为的问题,尽管我可以做更多的研究,但我还远远不能理解。

我假设读者已经阅读了最初的问题,并且知道OP的代码块和示例,但简而言之,OP正在尝试比较这两个数组,虽然结果很好,但比较函数的调用似乎不稳定:

$chomik = new chomik('a');
$a = array(5, $chomik, $chomik, $chomik);
$b = array($chomik, 'b', 'c', 'd');
array_diff_uassoc($a, $b, 'compare');

文件有点晦涩。。。但它确实声明:

如果第一个参数被认为分别小于、等于或大于第二个参数,则比较函数必须返回一个小于、等于、或大于零的整数。

据我所知,这意味着compare()函数应该更像这样:

function compare($a, $b) {
    echo("$a : $b<br/>");
    if($a === $b) return 0;
    else if ($a > $b) return 1;
    else return -1;
}

然而,这仍然给出了非常奇怪的结果,甚至有更多的"重复"

1:01:23:12:13:21:01:23:12:13:20:01:01:12:02:12:23:03:13:23:3

面对许多疑问,我阅读了compat-php函数,其中真正进行检查的部分很有趣:

foreach ($args[0] as $k => $v) {
    for ($i = 1; $i < $array_count; $i++) {
        foreach ($args[$i] as $kk => $vv) {
            if ($v == $vv) { // compare keys only if value are the same
                $compare = call_user_func_array($compare_func, array($k, $kk));
                if ($compare == 0) {
                    continue 3; // value should not be added to the result
                }
            }
        }
    }
    $result[$k] = $v;
}

这是的实际来源

此代码执行比较函数的方式不应该是输出我们看到的结果。Foreach无法在按键中来回移动(AFAIK??),就像这里第一个按键的顺序一样:

1:23:12:1

此外,如果值不匹配,它不应该检查密钥,那么为什么要检查所有这些:

1:23:12:13:2等

源代码中最顶层的foreach()如何通过键来回循环

为什么值不匹配的键仍在进行比较

foreach循环实际上是否在continued后仍继续执行

这是并发的一个例子吗是否可以以某种方式启动call_user_func_array,并实际执行比较函数的echo("$a : $b<br/>");,而不是按照它们"启动"的顺序??

我相信你已经确定了一个错误,我的朋友。我刚刚运行了你提到的问题中的代码,果不其然,它将键与不相同的值进行了比较。然而,我想测试源代码本身是否包含错误,所以我将array_diff_uassoc的官方源代码添加到了他的代码顶部,在我自己的命名空间中:

<?php
namespace mine;
// Code obtained from https://pear.php.net/reference/PHP_Compat-latest/__filesource/fsource_PHP_Compat__PHP_Compat-1.6.0a3CompatFunctionarray_diff_uassoc.php.html
function array_diff_uassoc()

{
    // Sanity check
    $args = func_get_args();
    if (count($args) < 3) {
        user_error('Wrong parameter count for array_diff_uassoc()', E_USER_WARNING);
        return;
    }

    // Get compare function
    $compare_func = array_pop($args);
    if (!is_callable($compare_func)) {
        if (is_array($compare_func)) {
            $compare_func = $compare_func[0] . '::' . $compare_func[1];
        }
        user_error('array_diff_uassoc() Not a valid callback ' .
            $compare_func, E_USER_WARNING);
        return;
    }

    // Check arrays
    $array_count = count($args);
    for ($i = 0; $i !== $array_count; $i++) {
        if (!is_array($args[$i])) {
            user_error('array_diff_uassoc() Argument #' .
                ($i + 1) . ' is not an array', E_USER_WARNING);
            return;
        }
    }

    // Compare entries
    $result = array();
    foreach ($args[0] as $k => $v) {
        for ($i = 1; $i < $array_count; $i++) {
            foreach ($args[$i] as $kk => $vv) {
                if ($v == $vv) {
               //   echo ("$v'n");
                    // echo ("$vv'n");
               //   echo ("$k'n");
                    // echo ("$kk'n");
                    // die();
                    $compare = call_user_func_array($compare_func, array($k, $kk));
                    if ($compare == 0) {
                        continue 3;
                    }
                }
            }
        }

        $result[$k] = $v;
    }
    return $result;
}
class chomik {
    public $state = 'normal';
    public $name = 'no name';
    public function __construct($name) {
        $this->name = $name;
    }
    public function __toString() {
        return $this->name . " - " . $this->state;
    }
}
function compare($a, $b) {
    echo("$a : $b'n");
    if($a != $b) {
        return 0;
    }
    else return 1;
}
$chomik = new chomik('a');
$a = array(5, $chomik, $chomik, $chomik);
$b = array($chomik, 'b', 'c', 'd');
array_diff_uassoc($a, $b, 'mine'compare');

这一次,它只比较了相等值的密钥:

1 : 0
2 : 0
3 : 0

奇怪吧?

根据此注释的powerword:

根据自定义比较函数要求您返回-1的事实判断;0;或者1,它似乎在两个数组之间进行比较之前或同时进行排序。

我被鼓励去阅读实际的php_array_diff()源,array_diff_uassoc()的注册函数,并发现它多次使用比较函数,我错误地将其解释为foreach通过键来回移动。


源代码中最顶层的foreach()如何通过键来回循环?!

没有只是用户提供的功能

diff_data_compare_func = php_array_user_compare;

多次用于对数据进行排序和评估。

[...]
zend_sort((void *) lists[i], hash->nNumOfElements,
            sizeof(Bucket), diff_data_compare_func, (swap_func_t)zend_hash_bucket_swap);
[...]
while (Z_TYPE(ptrs[i]->val) != IS_UNDEF && (0 < (c = diff_data_compare_func(ptrs[0], ptrs[i])))) {
[...]
if (diff_data_compare_func(ptrs[0], ptr) != 0) {
[...]

为什么值不匹配的键仍在进行比较?

的确,问题中发布的compat-pear代码暗示,如果valus不匹配,甚至不应该运行compare函数,但php_array_diff()的行为不同。


foreach循环真的会继续执行吗?这是并发的一个例子吗?

胡说八道。如果我是你,我会把它删掉。