array_intersect_key()用内置规则比较键名(===)。array_intersect_uassoc()同时比较键和值,键名用回调。那如果只想比较键名,但键名比较规则要自定义呢?
array_intersect_ukey()就是干这个的——通过用户提供的回调函数来比较键名,返回第一个数组中有且在其他所有数组中也存在的键名对应的值(值本身不参与比较,只是跟着键名一起返回)。这个函数从PHP 5.1开始可用。
语法格式
array array_intersect_ukey(array $array1, array $array2 [, array $... ], callable $key_compare_func): array
参数说明:
| 参数 | 说明 | 必填? |
|---|---|---|
| array1 | 基准数组 | 必填 |
| array2 | 第一个对比数组 | 必填 |
| array3... | 更多对比数组 | 可选 |
| key_compare_func | 用户自定义的回调函数,用于比较键名 | 必填 |
返回值: 返回一个数组,包含所有在array1中存在并且在所有其他数组中也存在的键名对应的条目(只比较键名,不比较值)。
三种键名相关交集函数的区别
| 函数 | 键名比较方式 | 值比较方式 | 用途 |
|---|---|---|---|
| array_intersect_key() | 内置=== |
不比较值 | 默认规则找键名交集 |
| array_intersect_uassoc() | 用户回调 | === |
自定义键名规则 + 值也要相等 |
| array_intersect_ukey() | 用户回调 | 不比较值 | 只自定义键名规则找交集 |
示例1:不区分大小写的键名比较
<?php
$user_data_v1 = [
"UserName" => "张伟",
"Email" => "zhang@test.com",
"Phone" => "13800000000",
"Age" => 25
];
$user_data_v2 = [
"username" => "wei.zhang",
"email" => "zhang@test.com",
"address" => "北京市朝阳区"
];
// 不区分大小写比较键名
$common = array_intersect_ukey($user_data_v1, $user_data_v2, "strcasecmp");
print_r($common);
?>
输出:
Array
(
[UserName] => 张伟
[Email] => zhang@test.com
)
注意:Phone和Age在v2中没有对应键名,address在v1中没有。UserName和username被视为匹配,Email和email也是。值不参与比较——虽然v1的Email值是"zhang@test.com",v2的email值也是"zhang@test.com",但这里其实没比较值,只是键名匹配上了。
示例2:多个数组比较
<?php
function key_compare($k1, $k2) {
// 去掉首尾空格后再比较
return strcmp(trim($k1), trim($k2));
}
$source_a = [
" id " => 101,
"name" => "产品A",
" price " => 299
];
$source_b = [
"id" => 102,
"name" => "产品B",
"stock" => 50
];
$source_c = [
" ID " => 103,
"name" => "产品C",
"category" => "电子"
];
$common_keys = array_intersect_ukey($source_a, $source_b, $source_c, "key_compare");
print_r($common_keys);
?>
输出:
Array
(
[ id ] => 101
[name] => 产品A
)
经过trim()处理后," id "、"id"、" ID "被视为相等;"name"也匹配上了。" price "在b和c中没有对应。
示例3:自定义复杂键名匹配(忽略前缀)
<?php
function ignore_prefix_compare($k1, $k2) {
// 去掉前缀"field_"后比较
$clean1 = str_replace("field_", "", $k1);
$clean2 = str_replace("field_", "", $k2);
return strcmp($clean1, $clean2);
}
$db_schema = [
"field_id" => "int",
"field_name" => "varchar",
"field_price" => "decimal",
"field_stock" => "int"
];
$api_response = [
"id" => 1001,
"name" => "机械键盘",
"price" => 299
];
$common_fields = array_intersect_ukey($db_schema, $api_response, "ignore_prefix_compare");
print_r($common_fields);
?>
输出:
Array
(
[field_id] => int
[field_name] => varchar
[field_price] => decimal
)
field_id匹配id,field_name匹配name,field_price匹配price。field_stock在API响应中没有。值只返回第一个数组的(int/varchar/decimal),不比较值本身。
个人经验分享
-
什么时候用array_intersect_ukey?
-
键名需要自定义相等规则(不区分大小写、忽略前缀、模糊匹配)
-
不关心值是否相等,只关心键名是否存在
-
和
array_diff_ukey()是对称操作(一个找交集,一个找差集)
-
-
和array_intersect_uassoc的重要区别
// array_intersect_ukey:只比较键名 $result = array_intersect_ukey($arr1, $arr2, 'strcasecmp'); // 键名匹配就保留,不管值是否相等 // array_intersect_uassoc:键名和值都要匹配 $result = array_intersect_uassoc($arr1, $arr2, 'strcasecmp'); // 键名匹配 && 值相等(===)才保留选哪个取决于你是否需要比较值。
-
性能方面
只比较键名不比较值,比array_intersect_uassoc快一些。大数据量下差异更明显。 -
常见使用场景
-
数据源结构对齐:找出多个数据源的公共字段
-
表单字段白名单(配合值处理)
-
版本兼容性检查:新数据是否包含旧数据的核心字段
-
示例4:代码号学习编程场景
<?php
// 场景:多个数据源的公共字段提取(字段名可能有大小写差异)
function field_compare($f1, $f2) {
return strcasecmp($f1, $f2); // 不区分大小写
}
$db_columns = [
"student_id" => "学生ID",
"student_name" => "学生姓名",
"student_score" => "成绩",
"student_class" => "班级"
];
$csv_headers = [
"Student_ID" => "学号",
"Student_Name" => "姓名",
"Student_Age" => "年龄"
];
$api_fields = [
"studentId" => "id",
"studentName" => "name",
"studentScore" => "score"
];
// 找出三个数据源都有的公共字段
$common = array_intersect_ukey($db_columns, $csv_headers, $api_fields, "field_compare");
echo "三个数据源都包含的字段:\n";
print_r($common);
// 找出只在数据库中有、其他数据源没有的字段
$db_only = array_diff_ukey($db_columns, $csv_headers, $api_fields, "field_compare");
echo "\n只在数据库中的字段:\n";
print_r($db_only);
?>
输出:
三个数据源都包含的字段:
Array
(
[student_id] => 学生ID
[student_name] => 学生姓名
)
只在数据库中的字段:
Array
(
[student_score] => 成绩
[student_class] => 班级
)
示例5:PHP 7+ 简洁回调写法
<?php
$arr1 = ["KEY_ONE" => "value1", "KEY_TWO" => "value2", "KEY_THREE" => "value3"];
$arr2 = ["key_one" => "val1", "key_two" => "val2", "key_four" => "val4"];
// 使用匿名函数 + 飞船运算符
$result = array_intersect_ukey($arr1, $arr2, function($a, $b) {
return strcasecmp($a, $b);
});
print_r($result);
?>
输出:
Array
(
[KEY_ONE] => value1
[KEY_TWO] => value2
)
示例6:数字和字符串键名的
<?php
function strict_compare($a, $b) {
// 这种比较下,整数1和字符串"1"被认为是不同的
return $a <=> $b;
}
function relaxed_compare($a, $b) {
// 先转字符串再比较,忽略类型差异
return strcmp((string)$a, (string)$b);
}
$arr1 = [1 => "apple", "2" => "banana", 3 => "cherry"];
$arr2 = ["1" => "fruit1", 2 => "fruit2", 3 => "fruit3"];
// 严格比较:1和"1"不同,"2"和2不同
$strict = array_intersect_ukey($arr1, $arr2, "strict_compare");
// 宽松比较:类型转换后比较
$relaxed = array_intersect_ukey($arr1, $arr2, "relaxed_compare");
echo "严格比较结果:\n";
print_r($strict);
echo "\n宽松比较结果:\n";
print_r($relaxed);
?>
输出:
严格比较结果:
Array
(
[3] => cherry
)
宽松比较结果:
Array
(
[1] => apple
[2] => banana
[3] => cherry
)
本节课程知识要点
-
array_intersect_ukey()用用户自定义回调函数比较键名,返回键名匹配的条目 -
和
array_intersect_key()的区别:后者用内置===比较键名 -
和
array_intersect_uassoc()的区别:后者同时比较值(===) -
回调函数必须返回整数(负数/0/正数)
-
只比较键名,不比较值(值原样返回)
-
可以传入多个数组进行比较
-
从PHP 5.1开始可用