array_udiff_assoc() 用於比較兩個或多個陣列的「鍵名」與「值」,並返回僅存在於第一個陣列中的鍵值對 (差集)。比較邏輯由使用者提供的回調函數決定,適合物件、複雜資料結構或需特定比較規則 (如大小寫不敏感、浮點數容差) 的場景。
array_udiff_assoc(
array $array1,
array $array2,
array ...$arrays,
callable $value_compare_func
): array
func(mixed $a, mixed $b): int,回傳 < 0、= 0、> 0 分別代表 $a 小於、等於、大於 $b。array_udiff() 僅比較值,本函數同時檢查鍵名是否相同。class CR {
private int $val;
public function __construct(int $v) { $this->val = $v; }
public static function cmp(CR $a, CR $b): int {
return $a->val <=> $b->val; // PHP 7+ 太空船運算子
}
}
$a = [
'0.1' => new CR(9),
'0.5' => new CR(12),
0 => new CR(23),
1 => new CR(4),
2 => new CR(-15),
];
$b = [
'0.2' => new CR(9), // 值相同但鍵名不同 → 視為差異
'0.5' => new CR(22), // 鍵名相同但值不同 → 差異
0 => new CR(3), // 鍵名相同值不同 → 差異
1 => new CR(4), // 鍵名、值皆同 → 不在差集
2 => new CR(-15), // 鍵名、值皆同 → 不在差集
];
$result = array_udiff_assoc($a, $b, [CR::class, 'cmp']);
print_r($result);
/* 輸出:
Array
(
[0.1] => CR Object ( [val:private] => 9 )
[0.5] => CR Object ( [val:private] => 12 )
[0] => CR Object ( [val:private] => 23 )
)
*/
解析:'1' => CR(4) 於兩陣列鍵名、值皆同,故被排除;'0.1' => CR(9) 與 '0.2' => CR(9) 值同但鍵名異,視為差異保留。
function array_udiff_assoc_recursive(array $a1, array $a2, callable $cmp): array
{
$diff = array_udiff_assoc($a1, $a2, $cmp);
foreach ($diff as $k => $v) {
if (is_array($v) && isset($a2[$k]) && is_array($a2[$k])) {
$diff[$k] = array_udiff_assoc_recursive($v, $a2[$k], $cmp);
if (empty($diff[$k])) unset($diff[$k]);
}
}
return $diff;
}
| 陷阱 | 說明 | 對策 |
|---|---|---|
| 回調回傳非整數 | 回傳 bool/float 會隱性轉型,導致邏輯錯誤 | 嚴格回傳 -1/0/1 或使用 <=> |
| 大量資料效能 | 回調函數會被頻繁呼叫,複雜邏輯拖慢速度 | 簡化比較邏輯、考慮預先正規化鍵值 |
| 鍵名型別差異 | '1' (string) vs 1 (int) 視為不同鍵 | 資料預處理統一鍵名型別 |
| 遞迴深度 | PHP 預設遞迴限制可能不足 | 調整 xdebug.max_nesting_level 或改迭代 |
| 函數 | 比較鍵名 | 比較值 | 比較方式 |
|---|---|---|---|
array_diff_assoc | 是 | 是 | 內建 === |
array_udiff | 否 | 是 | 回調 |
array_udiff_assoc | 是 | 是 | 回調 |
array_diff_uassoc | 是 | 是 | 鍵名回調、值內建 |
array_diff_ukey | 是 | 否 | 鍵名回調 |
array_udiff_assoc() 是處理結構化資料差異比對的利器。掌握「鍵名+值雙重檢查」與「回調函數邏輯設計」兩大核心,即可靈活應對物件陣列去重、設定檔變更偵測、API 回應差異分析等進階需求。記住:善用 <=> 簡化比較邏輯,必要時封裝遞迴版本處理多維結構。