← PHP中的array_diff_uassoc():用自定义回调函数比较键名的数组差集 PHP中的each():获取当前元素的键和值并移动指针 →

PHP中的array_diff_ukey():用自定义回调函数比较键名的数组差集(只比键)

原创 2026-05-22 PHP 已有人查阅

array_diff_key()用内置规则比较键名(===)。但有时候你需要自定义键名的比较逻辑——比如不区分大小写、忽略特殊符号、按数字大小而非字符串顺序来比。

array_diff_ukey()就是做这个的:通过用户提供的回调函数来比较键名,返回第一个数组中有、但其他数组中没有的条目。这个函数从PHP 5.1开始可用。

语法格式

array_diff_ukey(array $array1, array $array2 [, array $... ], callable $key_compare_func): array

参数说明:

参数 说明 必填?
array1 作为基准的数组 必填
array2 用来对比的数组 必填
array3... 更多用来对比的数组 可选
key_compare_func 用户自定义的回调函数,用于比较键名 必填

返回值: 返回一个数组,包含所有在array1中但不在其他数组中的条目。

回调函数的返回值规则

回调函数接收两个要比较的键名,返回:

  • 负数:第一个键名 < 第二个键名

  • 0:两个键名被视为相等

  • 正数:第一个键名 > 第二个键名

和array_diff_uassoc的区别

函数 比较范围 用途
array_diff_uassoc() 键名+值都用回调比 两个维度都需要自定义逻辑
array_diff_ukey() 只比键名 只需要自定义键名的比较规则

示例1:不区分大小写的键名比较

<?php
function case_insensitive_key_compare($k1, $k2) {
    return strcasecmp($k1, $k2);  // 不区分大小写比较字符串
}

$user_info_a = [
    "USERNAME" => "代码号001",
    "EMAIL" => "user001@test.com",
    "level" => 5,
    "SCORE" => 1280
];

$user_info_b = [
    "username" => "代码号001",   // 小写
    "email" => "user001@test.com",
    "level" => 5
];

$diff = array_diff_ukey($user_info_a, $user_info_b, "case_insensitive_key_compare");
print_r($diff);
?>

输出:

Array
(
    [SCORE] => 1280
)

键名"SCORE"在第二个数组中不存在(因为第二个只有username/email/level),所以返回。"USERNAME"和"EMAIL"虽然大小写不同,但回调函数把它们视为相等,所以被排除。

示例2:忽略前缀的比较(提取数字部分)

<?php
function ignore_prefix_compare($k1, $k2) {
    // 提取前缀后的数字部分进行比较
    $num1 = (int)str_replace("item_", "", $k1);
    $num2 = (int)str_replace("item_", "", $k2);
    
    if ($num1 === $num2) {
        return 0;
    }
    return ($num1 > $num2) ? 1 : -1;
}

$intory_new = [
    "item_101" => "键盘",
    "item_102" => "鼠标",
    "item_103" => "显示器",
    "item_105" => "耳机"
];

$intory_old = [
    "item_101" => "键盘",
    "item_102" => "鼠标",
    "item_104" => "摄像头"
];

$new_only = array_diff_ukey($intory_new, $intory_old, "ignore_prefix_compare");
print_r($new_only);
?>

输出:

Array
(
    [item_103] => 显示器
    [item_105] => 耳机
)

item_101和item_102在旧库中存在(虽然值可能不同,但这个函数只比较键名),所以被排除。item_103和item_105是新增的。

示例3:多个数组对比

<?php
function strict_key_compare($a, $b) {
    return $a <=> $b;  // PHP 7+ 飞船运算符
}

$master_product = [
    "p001" => "机械键盘",
    "p002" => "游戏鼠标",
    "p003" => "曲面显示器",
    "p004" => "降噪耳机",
    "p005" => "摄像头"
];

$warehouse_a = [
    "p001" => "机械键盘",
    "p002" => "游戏鼠标",
    "p003" => "曲面显示器"
];

$warehouse_b = [
    "p001" => "机械键盘",
    "p004" => "降噪耳机"
];

// 找出在任何仓库中都没有的商品
$not_in_any_warehouse = array_diff_ukey($master_product, $warehouse_a, $warehouse_b, "strict_key_compare");
print_r($not_in_any_warehouse);
?>

输出:

Array
(
    [p005] => 摄像头
)

p005在warehouse_a和warehouse_b中都没有出现,所以返回。

个人经验分享

  1. 什么时候用array_diff_ukey而不是array_diff_key?

    • 键名需要忽略大小写差异

    • 键名包含前缀/后缀需要剥离后比较

    • 键名是版本号("v1.2" vs "v1.10")需要按数字语义比较

    • 键名需要特殊规范化处理(如去掉空格、标点符号)

  2. 使用场景举例:

    // 场景:比较两个系统导出的数据,其中一个系统键名带下划线,另一个不带
    // 系统A: ["user_id" => 1, "user_name" => "张三"]
    // 系统B: ["userid" => 1, "username" => "张三"]
    // 自定义比较函数忽略下划线,认为user_id和userid是同一个键名
  3. 性能考虑
    自定义回调函数会有额外的函数调用开销。如果两个数组都很大(成千上万条),这个开销会变得明显。大数据量下,建议先用array_map()array_combine()预处理键名格式,再用array_diff_key()

  4. PHP 7+ 飞船运算符简化回调

    function _compare($a, $b) {
        return $a <=> $b;
    }

    一行搞定,效果和内置的===比较差不多。

  5. 和array_diff_uassoc容易搞混
    记住名字里的"u"后面跟什么:

    • array_diff_u**key** → 只比较键名(key)

    • array_diff_u**assoc** → 比较键名和值(assoc)

示例4:代码号学习编程场景

<?php
// 场景:比较两个学期选课记录,键名格式不同(学期前缀)
function compare_course_keys($k1, $k2) {
    // 去掉前缀 s1_、s2_ 后再比较
    $clean_k1 = str_replace(["s1_", "s2_"], "", $k1);
    $clean_k2 = str_replace(["s1_", "s2_"], "", $k2);
    return strcasecmp($clean_k1, $clean_k2);
}

$semester1 = [
    "s1_php" => "PHP基础",
    "s1_mysql" => "数据库设计",
    "s1_js" => "JavaScript入门",
    "s1_laravel" => "Laravel框架"
];

$semester2 = [
    "s2_php" => "PHP进阶",     // 同课程名,不同内容
    "s2_mysql" => "数据库优化",
    "s2_python" => "Python基础"  // 新课程
];

// 找出第一学期有但第二学期没有的课程(按课程名比较,忽略s1_/s2_前缀)
$only_in_s1 = array_diff_ukey($semester1, $semester2, "compare_course_keys");
print_r($only_in_s1);
?>

输出:

Array
(
    [s1_js] => JavaScript入门
    [s1_laravel] => Laravel框架
)

php和mysql在两个学期都存在(虽然值不同,但键名匹配上了),所以不返回。只有js和laravel是s1独有的。

示例5:数值类型键名的自定义比较

<?php
$scores_db = [95, 87, 92, 78, 88];
$scores_cache = [87, 92, 78];

// 键名就是索引0,1,2,3,4...
// 自定义比较:认为数值差距在1以内的键名视为相同
function fuzzy_key_compare($a, $b) {
    $diff = abs($a - $b);
    if ($diff <= 1) {
        return 0;  // 视为相等
    }
    return ($a > $b) ? 1 : -1;
}

$diff = array_diff_ukey($scores_db, $scores_cache, "fuzzy_key_compare");
print_r($diff);
?>

输出:

Array
(
    [0] => 95
    [3] => 78
    [4] => 88
)

这个例子比较特殊,实际中用得少。主要是说明回调函数可以写任何逻辑,不限于字符串比较。

本节课程知识要点

  • array_diff_ukey()自定义回调函数比较键名,返回第一个数组中独有的条目

  • array_diff_key()的区别:后者用内置的===比较

  • array_diff_uassoc()的区别:后者同时比较键名和值

  • 回调函数返回0时表示两个键名被视为相等

  • 可以传入多个数组进行比较

  • 从PHP 5.1开始可用

  • 典型场景:不区分大小写、忽略前缀/后缀、版本号比较

← PHP中的array_diff_uassoc():用自定义回调函数比较键名的数组差集 PHP中的each():获取当前元素的键和值并移动指针 →
分享笔记 (共有 篇笔记)
验证码:
微信公众号