繁体   English   中英

通过引用比较两个对象数组?

[英]Compare two arrays of objects by references?

我正在尝试使用array_udiff()计算两个对象数组的差。 我的对象结构很复杂,我不能依赖定量属性,因为两个数组中对象的那些属性可能具有相同的值,但是它们存储为不同的实例(这是预期的行为)。

所以,这是我的问题有什么方法可以使用引用检测在两个阵列中检测相同实例?

我尝试了什么?

我已经试过了:

<?php
header('Content-Type: text/plain; charset=utf-8');

$a = new stdClass;
$b = new stdClass;
$c = new stdClass;

$a->a = 123;
$b->b = 456;
$c->c = 789;

$x = [ $a, $c ];
$y = [ $b, $c ];

$func   = function(stdClass &$a, stdClass &$b){
    $replacer   = time();
    $buffer     = $a;

    $a = $replacer;

    $result = $a === $b;

    $a = $buffer;

    return $result;
};

$diff   = array_udiff($x, $y, $func);

print_r($diff);
?>

并获得了不成功的结果,因为如果我尝试替换$x元素的值,则php不会从$y删除引用。

我有相同的输出:

$func   = function(stdClass &$a, stdClass &$b){
    return $a === $b;
};

和为

$func   = function(stdClass &$a, stdClass &$b){
    return $a == $b;
};

它是一个空数组。

有什么建议么?

这是您的问题,来自手册页:

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

您正在返回布尔值( false ),因为您正在将时间戳与对象进行比较。 (int) false为零,因此每个对象将被视为相等,因此$diff数组为空。
将您的回调函数更改为:

$func = function(stdClass $a, stdClass $b)
{//don't pass by reference, it's quite dangerous
    $replacer = time();
    $buffer = $a;
    $a = $replacer;
    $result = $a === $b ? 0 : -1;//equal? return zero!
    $a = $buffer;
    return $result;
};

那会起作用,但是$diff现在显然会包含所有对象。 而且您的回调有点混乱,请考虑:

$func = function(stdClass $a, stdClass $b)
{//don't pass by reference, it's quite dangerous
    return $a === $b ? 0 : -1;//compare objects
    //or, if you want to compare to time, still:
    return time() === $b ? 0 : -1;
};

那真是个更加清洁的地狱,而且更短,不是吗?

注意
如果两个对象不相等,则必须返回-1 在这种情况下,返回1表示您正在比较的对象已经大于您要比较的对象的值。 在那种情况下,PHP只会停止查找,而只是假设您要与第一个数组进行比较的数组中不存在该值...好的,这变得相当复杂。 举个例子:

[$a, $c] compare to [$b, $c]:
$a === $b => false: returns 1
    PHP assumes $a > $b, so $a > $c is implied, $a is pushed into $diff
$c === $b => false returns 1
   PHP assumes $c > $b, and is pushed to $diff, it's never compared to the next elem...

但是,返回-1时返回false:

[$a, $c] compare to [$b, $c]:
$a === $b => false: returns -1
    PHP assumes $a < $b, so:
$a === $c => false: returns -1
    No more elems left, push $a to $diff
$c === $b => false returns -1
   PHP assumes $c < $b, moving on:
$c === $c => true returns 0
   Match found, $c is NOT pushed to $diff

如果更换,会发生什么:

$func   = function(stdClass &$a, stdClass &$b)

至:

function func(stdClass &$a, stdClass &$b)

并这样调用:

$diff   = array_udiff($x, $y, 'func');

尽管,我已经接受@ Elias Van Ootegem的回答,但对diff数组中的任何可能的对象组合都无济于事。

要检测引用,可以使用===!==比较运算符

当使用标识运算符 (===)时,对象变量仅当且仅当它们引用相同相同实例时才是相同的。

因此,这里是该函数,它接受两个数组,但可能会进行改进以接受更多数组:

function array_exclude_instances(array $source, array $excludes){
    foreach($source as $index => $current){
        foreach($excludes as $exclude){
            if($exclude !== $current)continue 1;

            unset($source[$index]);

            continue 2;
        }
    }

    return array_values($source);
}

测试:

$a = new stdClass;
$b = new stdClass;
$c = new stdClass;

$a->x = 123;
$b->x = 123;
$c->x = 456;

$x = [$a, $c];
$y = [$c, $b];

$result = array_exclude_instances($x, $y);

结果:

Array
(
    [0] => stdClass Object
        (
            [x] => 123
        )

)

在线测试@ 3v4l

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM