我刚刚阅读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有点模糊......但确实说明了:
如果第一个参数被认为分别小于,等于或大于,则比较函数必须返回小于,等于或大于零的整数。
据我了解,这意味着compare()
函数应该更像这样:
function compare($a, $b) {
echo("$a : $b<br/>");
if($a === $b) return 0;
else if ($a > $b) return 1;
else return -1;
}
然而,这仍然会产生非常奇怪的结果,甚至更多的重复&#34;
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
面对许多疑惑,我read the compat php function,以及检查实际发生的部分很有意思:
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()如何在键中来回循环?!
为什么仍然比较值不匹配的键?
foreach循环是否真的继续执行,即使它们已经continue
d?
这是并发的一个例子吗?可以以某种方式启动call_user_func_array并实际执行比较功能的echo("$a : $b<br/>");
,而不是按照它们的相同顺序执行#34;启动&#34; ??
答案 0 :(得分:1)
我相信你已经找到了一个错误,我的朋友。我刚刚在您引用的问题中运行了代码,果然,它比较了不相同的值的键。但是,我想测试源代码本身是否包含错误,所以我将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
奇怪,是吗?
答案 1 :(得分:0)
从自定义比较函数要求您返回-1的事实来看; 0;或者,它似乎是在两个数组之间进行比较之前或同时进行排序。
我很高兴为array_diff_uassoc()
阅读actual php_array_diff()
source,the registered function,并发现它多次使用比较功能,我错误地将其解释为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循环实际上是否继续执行,即使它们已经继续? 这是并发的一个例子吗?
无意义。如果我是你,我会编辑出来。