6

首先,我需要提到的是,我深入研究了手册和 php 文档,但没有找到答案。这是我使用的代码:

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<br/>");
    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, 'compare');

我的想法是,array_diff_uassoc 将比较这两个数组的所有值,如果值存在,则运行键比较。这段代码的输出是:

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

那么首先为什么有些对(1:0或3:1)是重复的?这是否意味着函数忘记了它已经比较了这些项目?我认为它会比较所有相等的值对,但我没有在输出中看到它。我错过了什么吗?

所以问题是:这个函数在比较顺序方面的确切行为是什么,为什么我看到这个重复?(我的 PHP 版本,如果有帮助的话:PHP 版本 5.3.6-13ubuntu3.6)

我真的很困惑,等待一些好的解释......

4

3 回答 3

0

op 的 评论中说

我只想要这些不在第二个数组中的元素 ($a[0])

你不能用array_diff($a, $b);吗?它返回

array(1) {
  [0]=>
  int(5)
}

否则,

该文件指出:

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

据我了解,这意味着该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

我问了另一个问题,因为它超出了答案的范围。

于 2015-04-02T19:58:44.783 回答
0

这确实有点耐人寻味。我在 github 上查找了 PHP 的最新源代码(你可能知道它是用 C++ 编写的)并试图理解它。(https://github.com/php/php-src/blob/master/ext/standard/array.c

快速搜索显示,有问题的函数是在第 4308 行声明的

PHP_FUNCTION(array_diff_uassoc)
{
    php_array_diff(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIFF_ASSOC, DIFF_COMP_DATA_INTERNAL, DIFF_COMP_KEY_USER);
}

所以这表明实际工作是由php_array_diff函数完成的,可以在第 3938 行的同一个文件中找到。在这里粘贴它有点长,准确地说是 265 行,但如果你愿意,可以查一下。

那是我放弃的地方。我在 C 方面没有任何经验,而且为时已晚,我已经厌倦了尝试理解它。我想首先进行键比较,因为它可能比比较值更有效,但这只是一个猜测。无论如何,他们这样做可能有一个很好的理由。

所有这些只是一个很长的介绍,你为什么要首先echo在你的compare函数中放置一个?的目标array_diff_uassoc是函数的输出。您不应该依赖解析器如何处理它。如果他们明天决定将该 C 函数的内部工作方式更改为 ie。先做值比较,你会得到完全不同的结果。

也许您可以使用这个用 php 编写的替换函数:http: //pear.php.net/reference/PHP_Compat-1.6.0a2/__filesource/fsource_PHP_Compat__PHP_Compat-1.6.0a2CompatFunctionarray_diff_uassoc.php.html

这样您就可以依靠行为不改变,并且您可以完全控制内部运作......

于 2015-04-02T21:19:32.917 回答
0

我认为您错过了返回值部分。

返回一个数组,其中包含 array1 中不存在于任何其他数组中的所有条目。

数组键用于比较。

文本中缺少的是比较仅以关联方式进行。这意味着任何自动声明或用户定义的数字键都被键入为字符串而不是整数。

所以随着

$one = array(a,b,c,'hot'=>d); // d has no match and  will be returned as array and go to the function alone
$two = array(a,b,c,d,e,f); //

因为 $one hot=>d 不匹配 $two 0=>d 在关联级别 $one hot=>d 被返回。

由于字符串和整数数据类型比较的 PHP 怪癖,用户定义的函数可用于通过使用更强大的比较操作(如 ===)来增强比较。

这有助于在类型不明确的情况下 '0'=>d 和 0=>d 可能看起来相似,但除非你在代码中这么说。

幸运的是,PHP7 的类型提示功能让我们摆脱了这种奇怪的结构和不清楚的文档。

我从我的评论中添加了这一点,因为它与您对哪种 php 结构最适合您的情况的理解有关。我的评论:

我不太确定,因为 if($a != $b) { 在他们的代码中是一个问题。因为他们在应该使用相同的运算符时错误地使用了相等性!==。他们在为关联键设计的结构中使用数字键。他们可能也不知道 array_udiff 更适合所涉及的数据

于 2015-04-02T20:51:14.937 回答