我刚刚读到关于奇怪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循环实际上是否在continue
d后仍继续执行
这是并发的一个例子吗是否可以以某种方式启动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循环真的会继续执行吗?这是并发的一个例子吗?
胡说八道。如果我是你,我会把它删掉。