PHP 8.1 中 array_unique() 不支持二维数组直接去重,因子数组不可哈希;可靠方法有三:① serialize+array_unique+unserialize(通用保键名);② array_column+array_intersect_key(按字段高效去重);③ foreach+严格全等判断(手动精准控制)。

PHP 8.1 中,array_unique() 本身不支持直接对二维数组去重,因为它只对一维数组的「值」做松散比较(==),而二维数组的子数组是不可哈希的标量类型(如 array、object),会触发警告并视作相同或失败。所以“保留原始键名”这个需求,必须建立在先将二维结构转化为可比形式的基础上,同时确保最终结果中每个子数组的原始键(如 '0', 'new', 'list')不被丢弃。
以下是几种在 PHP 8.1 下真正保留原始键名的可靠方法,按推荐度排序:
用 serialize + array_unique + unserialize(兼容性好,保留键名)
这是最通用、最稳妥的方式,适用于任意结构的二维数组(只要不含资源、闭包等不可序列化内容)。原理:把每个子数组转成唯一字符串 → 去重 → 再还原为数组。由于 `array_unique()` 在处理字符串时天然保留首次出现的键名,整个过程能完整继承原始键。
$arr = [
'0' => ['name' => 'james', 'age' => 30],
'1' => ['name' => 'susu', 'age' => 26],
'2' => ['name' => 'james', 'age' => 30], // 重复项
'new' => ['name' => 'kube', 'age' => 37],
'list'=> ['name' => 'kube', 'age' => 27],
];
// 步骤:序列化 → 去重 → 反序列化
$serialized = array_map('serialize', $arr);
$unique_serialized = array_unique($serialized);
$result = array_map('unserialize', $unique_serialized);
// ✅ 键名完全保留:'0', '1', 'new', 'list'('2' 被跳过)
print_r($result);用 array_column 提取唯一字段 + array_intersect_key(高效,需有业务主键)
如果你的二维数组中存在一个天然唯一标识字段(如 `'id'`、`'email'`、`'name'`),可借助键名自动覆盖机制,**零序列化开销,且严格保留原始键**。注意:该方法不是靠值去重,而是靠某列值作为“锚点”,通过键映射关系剔除重复锚点对应的整行。
立即学习“PHP免费学习笔记(深入)”;
function array_unique_by_column($arr, $column) {
if (empty($arr)) return $arr;
// 提取该列所有值,并用 array_flip 实现“去重+保留最后出现键” → 再 flip 回来取首次出现键
$values = array_column($arr, $column);
$flipped = array_flip($values); // 值→键,重复值的键会被后出现的覆盖
$unique_keys = array_keys($flipped); // 得到去重后的值列表
// 构建键映射:只保留第一次出现该 column 值的原始键
$keep_keys = [];
foreach ($arr as $k => $v) {
if (in_array($v[$column], $unique_keys) && !isset($keep_keys[$v[$column]])) {
$keep_keys[$v[$column]] = $k;
}
}
return array_intersect_key($arr, array_flip($keep_keys));
}
// 使用示例(按 name 去重,保留第一个同名项的原始键)
$result = array_unique_by_column($arr, 'name');
// 输出键为:'0', '1', 'new' —— '2' 和 'list' 因 name 已存在被跳过用 foreach + in_array(手动控制,键名 100% 自主)
适合小数据量或需要额外逻辑(如忽略大小写、部分字段比对)的场景。它不依赖任何隐式转换,**原始键名由你显式决定是否保留**。关键点:`in_array($item, $result, true)` 必须加第三个参数 `true`,否则 PHP 8.1 默认松散比较,可能把 `['a'=>1]` 和 `['a'=>'1']` 当作相同。
$result = [];
foreach ($arr as $key => $sub) {
// 严格全等判断:子数组是否已存在(含键名、类型、顺序)
$found = false;
foreach ($result as $existing) {
if ($sub === $existing) {
$found = true;
break;
}
}
if (!$found) {
$result[$key] = $sub; // ✅ 显式使用原始 $key,键名不丢失
}
}避免踩坑:array_unique 直接传二维数组无效
以下写法在 PHP 8.1 中会报 Warning,并返回错误结果:
```php // ❌ 错误!array_unique 不支持二维数组直接去重 $wrong = array_unique($arr); // Warning: Array to string conversion// ❌ 两次 array_flip 也失败:因为子数组不能当键 $flip1 = array_flip($arr); // Fatal error: Cannot use object of type array as key
不复杂但容易忽略:二维数组去重本质是「定义什么是重复」——是整行完全相等?还是某字段唯一?选对方法的前提,是先明确你的业务语义。



















