array_unique对多维数组无效,因其内部用==比较数组失败而静默保留原数组;推荐serialize+array_unique组合去重,或按字段用array_filter+$seen哈希表高效处理。
它根本不会去重,也不报错,只是静默跳过所有子数组——因为 PHP 内部尝试用 == 比较两个数组时失败,最终把整个子数组当“不可比”处理,原样保留。你看到的“没变化”,不是函数卡住,而是设计如此。
常见错误现象:array_unique([['id'=>1], ['id'=>1]]) 返回原数组;array_unique($multi, SORT_REGULAR) 也无效;PHP 8.3 依然不支持。
$flags 参数能起作用——多维数组本身就不在 array_unique 的支持范围内null、对象或资源,还会触发 Warning: Array to string conversion
把每个子数组转成唯一字符串再比,绕过类型限制。这是目前最通用、兼容性最好的做法,PHP 5.6 到 8.3 全支持。
示例代码:
立即学习“PHP免费学习笔记(深入)”;
$multi = [['id'=>1,'name'=>'Alice'], ['id'=>1,'name'=>'Alice'], ['id'=>2,'name'=>'Bob']];$unique = array_map('unserialize', array_unique(array_map('serialize', $multi)));
array_map('serialize', $multi) 把每个子数组变成字符串,如 a:2:{s:2:"id";i:1;s:4:"name";s:5:"Alice";}
array_unique 对这些字符串去重,天然支持array_map('unserialize', ...) 恢复成原始结构,键名和类型都保留serialize() 会失败,得提前过滤当你要的是“按某字段唯一”,而不是“整个子数组完全一致”时,serialize 就过度了。这时用 array_filter + $seen 哈希表更精准、更快。
示例(去重邮箱,忽略大小写):
$users = [['email'=>'[email protected]'], ['email'=>'[email protected]'], ['email'=>'[email protected]']];$seen = [];$unique = array_filter($users, function($u) use (&$seen) { $key = strtolower($u['email']); if (isset($seen[$key])) return false; $seen[$key] = true; return true;});
&$seen 引用传递,否则每次回调都是空数组isset($seen[$key]) 而不是 in_array($key, $seen),避免 O(n) 查找拖慢大数组array_values($unique)
isset($u['email']) 或 array_key_exists 防御10 万条记录下,serialize + array_unique 比手写 foreach + isset 慢 2–3 倍——前者要三次完整遍历(serialize、unique、unserialize),后者一次搞定。
$seen = []; $result = []; foreach ($arr as $item) { if (!isset($seen[$item['id']])) { $seen[$item['id']] = true; $result[] = $item; } }
null 或布尔型?不能直接当数组键,改用 $key = serialize($item['field'])
'1' 和 1),array_unique 默认松散比较会误判,手写逻辑可统一转类型再比真正麻烦的从来不是怎么写,而是你是否意识到:array_unique 的“失效”,往往是因为你传给它的根本就不是它能处理的东西。