← PHP array_udiff函数:PHP数组差集运算与自定义回调比较 PHP array_uintersect_assoc函数详解:带键名校验的自定义交集运算 →

PHP array_udiff_uassoc函数:PHP键值双重回调数组差集运算

著
原创 2026-10-09 PHP 已有人查阅

PHP的数组差集函数有好几个变体,array_udiff_uassoc()是其中比较特别的一个。它要求开发者提供两个回调函数:一个负责比较数组的值,另一个负责比较数组的键。只有键和值同时匹配,才认为两个元素相等。这个函数从PHP5.0开始提供,适合处理那些键名和键值都需要按自定义规则判断的场景。

语法与参数

array array_udiff_uassoc(
    array $array1,
    array $array2,
    [, array $... ],
    callable $value_compare_func,
    callable $key_compare_func
);

参数说明:

参数 说明 是否必须
array1 基准数组,差集结果以此数组为准 是
array2 参与比较的数组 是
array3,... 更多参与比较的数组 否
value_compare_func 比较数组值的回调函数 是
key_compare_func 比较数组键的回调函数 是

两个回调函数都必须返回整数:小于0表示第一个参数小于第二个参数,等于0表示相等,大于0表示大于。这个约定和strcmp()一致。

双回调机制的理解

array_udiff_uassoc()的比较逻辑可以拆成两步:

第一步,用key_compare_func判断两个元素的键是否相等。如果键不相等,直接认为这两个元素不同,不需要再比较值。

第二步,如果键相等,再用value_compare_func判断值是否相等。值也相等,才认定两个元素匹配。

这个顺序意味着:键的比较优先级高于值。即使两个元素的值相同,只要键不同,就不会被视为相等。

与array_udiff的区别

array_udiff()只比较值,不比较键。返回结果保留第一个数组的键名,但键名不参与比较。

array_udiff_uassoc()同时比较键和值,两者都相等才排除。返回结果同样保留第一个数组的键名。

array_udiff_assoc()比较键和值,但值用内置规则比较,键用回调比较。

array_udiff_uassoc()则是键和值都交给回调,灵活性较高。

代码号学习编程:基础示例

<?php
function compareValue($a, $b)
{
    if ($a === $b) {
        return 0;
    }
    return ($a > $b) ? 1 : -1;
}

function compareKey($a, $b)
{
    if ($a === $b) {
        return 0;
    }
    return ($a > $b) ? 1 : -1;
}

$mobile1 = ["a" => "samsung", "b" => "oppo", "c" => "vivo"];
$mobile2 = ["a" => "samsung", "b" => "oppo", "c" => "micromax"];

$result = array_udiff_uassoc($mobile1, $mobile2, "compareValue", "compareKey");
print_r($result);

输出:

Array
(
    [c] => vivo
)

键a、b、c在两个数组中都存在。键a和b对应的值相同,被排除。键c的值不同,保留下来。

键相同但值不同

<?php
function compareValue($a, $b)
{
    return ($a === $b) ? 0 : (($a > $b) ? 1 : -1);
}

function compareKey($a, $b)
{
    return ($a === $b) ? 0 : (($a > $b) ? 1 : -1);
}

$news1 = ["a" => "aajtak", "b" => "zee news", "c" => "ndtv"];
$news2 = ["a" => "aajtak", "b" => "zee news", "c" => "zee news"];

$result = array_udiff_uassoc($news1, $news2, "compareValue", "compareKey");
print_r($result);

输出:

Array
(
    [c] => ndtv
)

键c在两个数组中都存在,但值不同,所以保留。

键不同但值相同

这是array_udiff_uassoc()和array_udiff()行为差异最明显的地方。

<?php
function compareValue($a, $b)
{
    return ($a === $b) ? 0 : (($a > $b) ? 1 : -1);
}

function compareKey($a, $b)
{
    return ($a === $b) ? 0 : (($a > $b) ? 1 : -1);
}

$lang1 = ["m" => "C", "n" => "Java", "o" => "C#"];
$lang2 = ["m" => "C", "b" => "Java", "c" => "C#"];

$result = array_udiff_uassoc($lang1, $lang2, "compareValue", "compareKey");
print_r($result);

输出:

Array
(
    [n] => Java
    [o] => C#
)

Java和C#的值在lang2中都存在,但键不同。lang1中是n和o,lang2中是b和c。键不匹配,所以这些元素不会被视为相等,保留在结果中。

如果用array_udiff(),结果会不同——它只看值,Java和C#会被排除。

项目实战反思:配置项对比场景

在一个配置管理系统中,需要对比两个版本的配置文件,找出当前版本中新增或修改的配置项。配置数据是关联数组,键是配置项名称,值是配置内容。

最初用了array_diff_assoc(),但它用内置规则比较,遇到数组类型的配置值时会报错。后来改用array_udiff_uassoc(),在值比较回调里用serialize()把数组转成字符串再比较:

<?php
function compareConfigValue($a, $b)
{
    $aStr = is_array($a) ? serialize($a) : (string)$a;
    $bStr = is_array($b) ? serialize($b) : (string)$b;
    return strcmp($aStr, $bStr);
}

function compareConfigKey($a, $b)
{
    return strcmp($a, $b);
}

$oldConfig = [
    'site_name' => '代码号学习编程',
    'debug_mode' => false,
    'cache' => ['type' => 'redis', 'ttl' => 3600],
];

$newConfig = [
    'site_name' => '代码号学习编程',
    'debug_mode' => false,
    'cache' => ['type' => 'memcache', 'ttl' => 1800],
];

$changed = array_udiff_uassoc($newConfig, $oldConfig, 'compareConfigValue', 'compareConfigKey');
print_r($changed);

输出:

Array
(
    [cache] => Array
        (
            [type] => memcache
            [ttl] => 1800
        )
)

这个例子里,键比较和值比较都用了strcmp(),它返回整数,符合回调函数的返回值要求。

踩过的坑:最初值比较回调里直接用了===,返回布尔值。array_udiff_uassoc()期望整数返回值,布尔值true会被当作1,false会被当作0,导致比较结果不符合预期。后来改成三元运算符返回1、0、-1才正常。

另一个坑是回调函数的参数顺序。值比较回调接收的两个参数是元素的值,键比较回调接收的两个参数是元素的键。如果写反了,比较逻辑就错了。

个人建议:选用原则

array_udiff_uassoc()的灵活性来自双回调,但代价是每次比较都要调用两次用户函数,性能开销比array_diff()和array_udiff()都要大。数据量大的时候要谨慎。

适合的场景:

  • 关联数组,键和值都需要按自定义规则比较

  • 值可能是数组或对象,需要序列化后比较

  • 键的比较需要忽略大小写或按特定规则排序

  • 业务上“相等”的定义同时涉及键和值

不适合的场景:

  • 简单标量数组,用array_diff()或array_diff_assoc()即可

  • 只需要比较值,用array_udiff()

  • 只需要比较键,用array_diff_key()或array_udiff_assoc()

  • 数据量极大且对性能敏感,考虑先建立哈希索引再对比

本节课程知识要点

  • array_udiff_uassoc()同时用两个回调函数比较键和值,两者都相等才排除元素

  • 键比较优先级高于值比较,键不相等时不再比较值

  • 两个回调函数都必须返回整数,不能返回布尔值

  • 返回结果保留第一个数组的键名

  • 适合关联数组、复杂值类型、自定义键值比较规则的场景

  • 性能开销高于单回调版本,数据量大时需评估

进阶示例:忽略大小写的键值比较

<?php
function compareValueIgnoreCase($a, $b)
{
    return strcasecmp((string)$a, (string)$b);
}

function compareKeyIgnoreCase($a, $b)
{
    return strcasecmp((string)$a, (string)$b);
}

$array1 = ["Name" => "Alice", "Age" => "30", "City" => "Beijing"];
$array2 = ["name" => "alice", "age" => "30", "city" => "Shanghai"];

$result = array_udiff_uassoc($array1, $array2, "compareValueIgnoreCase", "compareKeyIgnoreCase");
print_r($result);

输出:

Array
(
    [City] => Beijing
)

strcasecmp()忽略大小写比较字符串,返回整数。Name/name和Age/age在忽略大小写后键相等,值也相等,被排除。City/city键相等,但值不同,保留。

array_udiff_uassoc()是PHP数组差集函数中比较维度最细的一个。它把键和值的比较权都交给开发者,适合处理结构复杂、比较规则特殊的关联数组。理解双回调的调用顺序、返回值约定以及性能边界,能在项目中做出更合适的选择。

← PHP array_udiff函数:PHP数组差集运算与自定义回调比较 PHP array_uintersect_assoc函数详解:带键名校验的自定义交集运算 →
分享笔记 (共有 篇笔记)
验证码:
微信公众号