array_diff_assoc()用内置的比较规则判断键名是否相等(===)。但有时候你需要自定义比较逻辑——比如键名不区分大小写比较,或者用自定义的字符串比较规则。
array_diff_uassoc()就是干这个的:通过用户提供的回调函数来比较键名,返回第一个数组中有但其他数组中没有的条目(键名+值)。这个函数从PHP 5开始可用。
语法格式
array_diff_uassoc(array $array1, array $array2 [, array $... ], callable $key_compare_func): array
参数说明:
| 参数 | 说明 | 必填? |
|---|---|---|
| array1 | 作为基准的数组 | 必填 |
| array2 | 用来对比的数组 | 必填 |
| array3... | 更多用来对比的数组 | 可选 |
| key_compare_func | 用户自定义的回调函数,用于比较键名 | 必填 |
返回值: 返回一个数组,包含所有在array1中但不在其他数组中的条目。
回调函数的要求
回调函数接收两个参数(两个要比较的键名),返回:
-
负数:第一个键名小于第二个键名
-
0:两个键名相等
-
正数:第一个键名大于第二个键名
示例1:基础用法——自定义整数比较
<?php
function compare_keys($k1, $k2) {
if ($k1 === $k2) {
return 0;
}
return ($k1 > $k2) ? 1 : -1;
}
$config_default = [
"host" => "localhost",
"port" => 3306,
"username" => "root",
"timeout" => 30
];
$config_custom = [
"HOST" => "db.example.com", // 注意大小写
"PORT" => 3307,
"username" => "app_user",
"charset" => "utf8"
];
$diff = array_diff_uassoc($config_default, $config_custom, "compare_keys");
print_r($diff);
?>
输出:
Array
(
[host] => localhost
[port] => 3306
[timeout] => 30
)
因为默认比较(===)下,"host"和"HOST"不同,所以host、port、timeout都返回了。如果要用不区分大小写的比较,看下一个例子。
示例2:不区分大小写的键名比较
<?php
function case_insensitive_compare($k1, $k2) {
// 转成小写后再比较
$k1_lower = strtolower($k1);
$k2_lower = strtolower($k2);
if ($k1_lower === $k2_lower) {
return 0;
}
return ($k1_lower > $k2_lower) ? 1 : -1;
}
$required_fields = ["USERNAME", "EMAIL", "PASSWORD"];
$submitted_data = [
"username" => "代码号001",
"email" => "user@test.com"
// 没有password字段
];
$missing = array_diff_uassoc($required_fields, $submitted_data, "case_insensitive_compare");
print_r($missing);
?>
输出:
Array
(
[PASSWORD] =>
)
array_diff_uassoc要求两个数组的结构相同才能正常工作。这个例子其实不太合适,更好的做法是用array_udiff_assoc。实际中更常见的是用array_diff_key结合array_change_key_case。
个人建议: 如果需要不区分大小写比较键名,更简单的做法是用array_change_key_case()先把两个数组的键名统一转成小写,然后用普通的array_diff_assoc()。代码更清晰:
$normalized = array_change_key_case($submitted_data, CASE_LOWER);
$required_lower = array_change_key_case($required_fields, CASE_LOWER);
示例3:多个数组对比
<?php
function strict_compare($a, $b) {
// 严格类型比较
return $a <=> $b; // PHP 7+ 的三元比较运算符
}
$team_leader = [
"id" => 1001,
"name" => "张伟",
"role" => "leader",
"department" => "技术部"
];
$team_member_a = [
"id" => 1002,
"name" => "李芳",
"role" => "developer"
];
$team_member_b = [
"id" => 1003,
"name" => "王磊"
];
$unique_to_leader = array_diff_uassoc($team_leader, $team_member_a, $team_member_b, "strict_compare");
print_r($unique_to_leader);
?>
输出:
Array
(
[department] => 技术部
)
只有"department"这个键名是leader独有的,id、name、role在其他数组中也都存在(不管值是什么)。
个人经验分享
-
什么时候需要array_diff_uassoc?
-
键名需要自定义比较规则(不区分大小写、特殊字符串比较、版本号比较等)
-
内置的
===比较不够用的时候 -
很少用,大多数场景用
array_diff_assoc就够了
-
-
常见坑:返回值类型
回调函数必须返回整数(负数、0、正数)。返回布尔值会出现奇怪的结果。 -
性能考虑
自定义回调函数会有额外的函数调用开销。如果只需要不区分大小写,建议先统一转换键名再用array_diff_assoc,性能更好。 -
PHP 7+ 的比较运算符
PHP 7 引入了<=>(飞船运算符),可以简化回调函数:function compare($a, $b) { return $a <=> $b; }这个运算符自动返回-1、0、1。
-
实际应用场景
我工作中用到array_diff_uassoc的场景很少。一个比较实用的例子是比较两个配置数组时,忽略某些键名的大小写差异。
示例4:代码号学习编程场景
<?php
// 场景:比较两个版本的API字段,键名包含版本号需要自定义比较
function version_key_compare($k1, $k2) {
// 提取数字部分进行比较
preg_match('/\d+/', $k1, $m1);
preg_match('/\d+/', $k2, $m2);
$v1 = isset($m1[0]) ? (int)$m1[0] : 0;
$v2 = isset($m2[0]) ? (int)$m2[0] : 0;
if ($v1 === $v2) {
return 0;
}
return ($v1 > $v2) ? 1 : -1;
}
$api_v1 = [
"user_v1" => ["name", "email"],
"order_v1" => ["id", "amount"],
"product_v1" => ["sku", "price"]
];
$api_v2 = [
"user_v2" => ["name", "email", "phone"],
"order_v2" => ["id", "amount", "status"]
];
$diff = array_diff_uassoc($api_v1, $api_v2, "version_key_compare");
echo "只在V1中存在的接口:\n";
print_r($diff);
?>
输出:
只在V1中存在的接口:
Array
(
[product_v1] => Array
(
[0] => sku
[1] => price
)
)
示例5:最简单的回调写法
<?php
$arr1 = ["a" => 1, "b" => 2, "c" => 3];
$arr2 = ["A" => 1, "b" => 2];
// 不区分大小写比较
$result = array_diff_uassoc($arr1, $arr2, function($k1, $k2) {
return strcasecmp($k1, $k2); // PHP内置的不区分大小写字符串比较
});
print_r($result);
?>
输出:
Array
(
[c] => 3
)
strcasecmp()本身已经返回符合要求的值(负数、0、正数),可以直接作为回调函数使用。
本节课程知识要点
-
array_diff_uassoc()用自定义回调函数比较键名,返回第一个数组中独有的条目 -
和
array_diff_assoc()的区别:后者用内置的===比较键名 -
回调函数必须返回整数(负数/0/正数)
-
可以传入多个数组进行比较
-
只比较键名,不比较值(值的比较是
array_udiff_assoc()的事) -
从PHP 5开始可用
-
大多数情况下
array_diff_assoc()够用,需要自定义规则时才用这个