簡體   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