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

标签 php arrays

我刚刚读了that question关于奇怪的 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');

The documentation有点晦涩……但它确实指出:

The comparison function 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.

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

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

然而这仍然会产生非常奇怪的结果,甚至有更多的“重复”

1 : 0
1 : 2
3 : 1
2 : 1
3 : 2
1 : 0
1 : 2
3 : 1
2 : 1
3 : 2
0 : 0
1 : 0
1 : 1
2 : 0
2 : 1
2 : 2
3 : 0
3 : 1
3 : 2
3 : 3

faced with many doubts, I read the compat php function, and the part where the check actually happens is interesting:

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

here's the actual source (根据 comment )

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

1 : 2
3 : 1
2 : 1

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

1 : 2
3 : 1
2 : 1
3 : 2
etc...

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

为什么值不匹配的键还要进行比较?

foreach 循环实际上会继续执行,即使它们已被 continue d?

这是并发的例子吗? call_user_func_array 可以以某种方式启动并实际执行 echo("$a : $b<br/>"); 吗?比较功能的顺序与它们“启动”的顺序不同??

最佳答案

我相信你已经查明了一个错误,我的 friend 。我刚刚运行了您引用的问题中的代码,果然,它比较了不相同的值的键。但是,我想测试源代码本身是否包含错误,所以我将 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

奇怪吧?

关于php - 为什么 array_diff_uassoc 比较值不匹配的键,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29421414/

相关文章:

java - HttpURLConnection 未按预期响应

php - 规范化多字节 php 字符串中的整数值

javascript - 使 javascript 数组中的值之间的距离彼此相等

android - 将数组 Gson 提取为 JSON

c++ - 仅对数组中列的值求和

arrays - 什么是一致数组?

javascript - 更改 ID 加载的背景

php - 如何从.env变量处理%kernel.project_dir%?

PHP MySQL Group By 使用给定的数组

php - Netbeans 中的 Yii 框架 - 对象方法自动完成未出现