PHP8:优雅且高效地递增未设置的数组索引
PHP7与PHP8数组键统计的差异及性能问题
在PHP7中,以下代码虽不规范,但可读性强,可实时按键统计内容(如重索引算法场景);但PHP8中直接运行会因数组索引未设置触发警告:
$keylist = array('keyA','keyB','keyA','keyA'); $idx_count = array(); foreach ($keylist as $thiskey){ $idx_count[$thiskey]++; }
PHP8的常见兼容实现方式
使用isset()检查
$keylist = array('keyA','keyB','keyA','keyA'); $idx_count = array(); foreach ($keylist as $thiskey){ if (!isset($idx_count[$thiskey])){ $idx_count[$thiskey] = 0; } $idx_count[$thiskey]++; }
使用empty()检查
$keylist = array('keyA','keyB','keyA','keyA'); $idx_count = array(); foreach ($keylist as $thiskey){ if (empty($idx_count[$thiskey])){ $idx_count[$thiskey] = 0; } $idx_count[$thiskey]++; }
使用分支判断
$keylist = array('keyA','keyB','keyA','keyA'); $idx_count = array(); foreach ($keylist as $thiskey){ if (!isset($idx_count[$thiskey])){ $idx_count[$thiskey] = 1; }else{ $idx_count[$thiskey]++; } }
使用空合并运算符
$keylist = array('keyA','keyB','keyA','keyA'); $idx_count = array(); foreach ($keylist as $thiskey){ $idx_count[$thiskey] ??= 0; $idx_count[$thiskey]++; }
技术问题解答
1. 超大$keylist场景下各方案的性能影响
PHP7中直接自增的逻辑,内部是首次访问未定义索引时自动初始化值为0再自增,后续仅执行自增操作,只有首次处理某个键时存在隐式初始化开销。
PHP8的几种方案均需在每次循环中做额外存在性判断,性能差异如下:
isset()和空合并运算符??=的判断逻辑最轻量:isset()直接检查变量是否存在且不为null,底层实现高效;??=是语法糖,本质与isset()判断等价,性能几乎一致。empty()的判断逻辑更复杂,会额外校验值是否为“空值”(如0、空字符串等),不仅可能在统计值为0时出现错误初始化,性能也比isset()略差。- 分支判断写法首次赋值为1,避免了“设0再加1”的两步操作,首次处理键时步骤更少,但每次循环仍需
isset()判断,整体性能与isset()方案接近。
对于超大$keylist:若键重复率极高,额外判断的开销占比极低;若键唯一性极高,判断开销会累积,但PHP底层对这类操作做了优化,实际性能差异不会特别夸张,其中empty()方案是性能最差的。
2. 兼顾可读性与性能的优雅实现
有两种合适的方式:
- 空合并运算符简化写法:写法简洁,可读性接近PHP7原始代码,性能与
isset()方案一致,是PHP8通用场景的最优选择:
$keylist = array('keyA','keyB','keyA','keyA'); $idx_count = array(); foreach ($keylist as $thiskey){ $idx_count[$thiskey] = ($idx_count[$thiskey] ?? 0) + 1; }
- 内置函数
array_count_values():纯统计场景下,直接使用PHP内置的C实现函数,性能远高于手动循环,可读性拉满:
$keylist = array('keyA','keyB','keyA','keyA'); $idx_count = array_count_values($keylist);
注:array_count_values()仅支持字符串或整数类型的数组值,无法处理自定义统计逻辑的场景。
内容的提问来源于stack exchange,提问作者sanguinarium
相关产品推荐
相关产品推荐

