php8中array_unique()不能直接递归去重多维数组,因其将子数组转为字符串"array"导致误删;需用serialize()+递归处理实现结构级去重,注意不可序列化对象、键名保留及浮点精度等边界问题。

PHP8 中递归去重多维数组为什么不能直接用 array_unique()
array_unique() 在 PHP8 里仍只支持一维数组,对嵌套的 array 类型值会直接当作 Array 字符串处理(PHP 将其转为字符串 "Array"),导致所有子数组被判定为“相同”,最终只剩一个——这不是去重,是误删。
真正要比较的是子数组的结构和内容是否完全一致,必须逐层展开、序列化或递归比对。
用 serialize() + array_keys() 实现稳定递归去重
这是最常用且兼容性好的方式:把每个子数组序列化成唯一字符串,去重后再反序列化。注意需配合 is_array() 判断层级,避免对非数组项(如字符串、数字)误序列化。
- 对当前层级是数组的元素,先递归处理其子项,再
serialize()整个结果 - 用
array_keys(array_flip(...))或array_values(array_unique(..., SORT_REGULAR))去重(后者在 PHP8 对序列化字符串更可靠) - 最后用
unserialize()恢复结构——但注意:若原数组含不可序列化对象(如Closure、资源句柄),此法会失败
// 示例:递归去重多维数组
function array_unique_recursive($arr) {
if (!is_array($arr)) return $arr;
$serialized = [];
$unique = [];
foreach ($arr as $item) {
$item = array_unique_recursive($item); // 先递归处理子项
$s = serialize($item);
if (!in_array($s, $serialized)) {
$serialized[] = $s;
$unique[] = $item;
}
}
return $unique;
}
PHP8.1+ 可用 match + array_reduce 提升可读性(但不推荐用于深层嵌套)
如果数组结构较浅(比如最多三层),可用 match 分支处理不同类型,配合 array_reduce 累积唯一值。但它无法替代真正的递归逻辑,只是让类型分发更清晰。
-
match本身不递归,只是语法糖,仍需手动调用自身 - 对含
null、NaN或浮点精度差异的数组,serialize()仍是更稳妥的比较依据 - 若数组键名重要(如关联键需保留),上述
serialize方案默认丢弃键名;需改用foreach+===深比较,但性能下降明显
容易被忽略的边界情况
实际数据中常出现这些陷阱,不处理会导致去重失效或报错:
- 数组中混有
null、false、空字符串,它们在serialize()后字符串不同,但业务上可能视为等价——需提前标准化 - 浮点数精度问题:
0.1 + 0.2和0.3在 PHP 中不恒等,serialize()会区分,必要时应四舍五入后处理 - 含对象的数组:默认
serialize()会包含类名和属性,若对象未实现__serialize(),可能暴露敏感信息或引发异常 - 超深嵌套(>100 层)可能触发 PHP 递归限制,需检查
xdebug.max_nesting_level或改用栈模拟递归
真正难的不是写递归函数,而是判断“什么算重复”——结构相同?键值对相同?忽略顺序?这些业务语义必须在序列化前就定义清楚。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











