array_count_values()适用于一维标量数组的值频次统计,如$types=['book','movie','book']→['book'=>2,'movie'=>1];多维或复杂结构需foreach+isset()或array_reduce()手动聚合,并注意排序与空值处理。

用 array_count_values() 统计数组中分类值出现次数
最直接的场景是:你有一组原始数据(比如商品类型列表 $types = ['book', 'movie', 'book', 'game', 'movie']),想快速知道每种类型各出现几次。这时候 array_count_values() 是首选,它专为这种“值频次统计”设计,一行搞定,不需手写循环。
注意它只接受一维数组,且键会被忽略、只统计值;如果值是数组或对象,会报 Warning: array_count_values(): Can only count STRING and INTEGER values!。
- 输入必须是纯标量值(
string或int),浮点数会被截断为整数 - 区分大小写:
'Book'和'book'算两个不同分类 - 若需忽略大小写,先用
array_map('strtolower', $arr)预处理
遍历关联数组时用 foreach + isset() 累加计数器
当你在处理结构更复杂的数组(比如从数据库查出的多维记录),需要按某个字段(如 category_id)分组统计时,手动遍历 + 累加更灵活。核心是初始化空数组,然后对每个分类值做存在性判断再自增。
示例:
立即学习“PHP免费学习笔记(深入)”;
$data = [
['name' => 'A', 'category_id' => 1],
['name' => 'B', 'category_id' => 2],
['name' => 'C', 'category_id' => 1],
];
$count = [];
foreach ($data as $item) {
$cat = $item['category_id'];
if (!isset($count[$cat])) {
$count[$cat] = 0;
}
$count[$cat]++;
}
// 结果:[1 => 2, 2 => 1]
- 用
isset()而非empty(),因为$count[1]初始为0,empty(0)为 true,会导致误判 - 若分类字段可能缺失(如
$item['category_id']不存在),应先用isset($item['category_id'])做防御检查 - 这种写法天然支持任意键类型(字符串、整数、甚至布尔值),比
array_count_values()更通用
用 array_reduce() 函数式风格一次性聚合
如果你倾向函数式写法,或者想在管道中链式处理(比如配合 array_filter() 后续筛选),array_reduce() 可以把统计逻辑压缩成一个表达式,避免显式声明临时变量。
示例(同上数据):
$count = array_reduce($data, function ($carry, $item) {
$cat = $item['category_id'] ?? null;
if ($cat !== null) {
$carry[$cat] = ($carry[$cat] ?? 0) + 1;
}
return $carry;
}, []);
-
$carry是累计器,初始值由第三个参数[]指定 -
?? 0替代isset()判断,更简洁,但 PHP 版本需 ≥ 7.0 - 性能略低于原生
foreach,但代码密度高;可读性取决于团队是否熟悉函数式习惯
统计结果排序或取 Top N 时别漏掉 ksort() 或 arsort()
统计完得到的 $count 数组,键是分类标识,值是数量。但默认顺序是插入顺序,不是按数量大小或分类名排序——这点容易被忽略,导致前端展示错乱或导出数据不符合预期。
- 按分类名升序排(如字母顺序):用
ksort($count) - 按数量降序排(Top N):用
arsort($count),之后可用array_slice($count, 0, 5)取前 5 名 - 如果分类是中文或需要自然排序,得用
uksort($count, 'strnatcmp')或自定义比较函数
实际项目里,统计只是中间步骤,后续怎么组织、排序、过滤这些结果,往往比统计本身更容易出问题。



















