购物车结算前要去掉最后一条临时商品,同事写了 unset 加 count 减一,本地测着没问题,接口返回的 JSON 到了前端变成对象,前端按数组遍历直接报错。原因不在删除这一步,在删除之后数组的键没重排。
unset 的问题在哪
unset 只把那个键值对摘掉,索引原样保留。一个三元素数组删掉下标 2 的那项之后,剩下的键是 0 和 1,看着还是连续。删中间某一项才是真正的坑:键变成 0 和 2,json_encode 判定它不是顺序数组,输出成带键名的对象。
推荐用 array_pop
一行搞定,返回被删掉的值,同时把内部指针和长度都更新掉,剩下的键自然连续:
$last = array_pop($cart);空数组上调用不会报错,返回 null,所以前面加个 empty 判断更清楚。这个方法的时间复杂度是常数级,不管数组多大都一样快,比 unset 加重新索引省事得多。
其他几种写法什么时候用
- array_splice 传负一,删掉末尾并重建索引,适合同时要处理中间某段的情况。
- array_slice 取前 n 减一个,返回新数组,原数组不动,需要保留原数据时用。
- 关联数组同样可以用 array_pop,键名是什么都无所谓,删的就是最后插入的那个。
- 如果要删的是第一个,对应 array_shift,注意它会把所有键重排,大数组上有性能开销。
两个容易忽略的细节
用引用赋值的数组,pop 之后原数组也会变,改动前先确认变量关系。多维数组里 pop 出来的是一整个子数组,想删子数组里的元素得再进去操作一次。
取最后一个元素但不想删,用 end 加 current,或者直接下标取 count 减一。end 会把内部指针移到末尾,后续用 each 或 next 遍历会受影响,遍历前记得 reset。
写接口的项目统一用 array_pop,能省掉一类只在特定数据下才复现的 JSON 结构问题。另外 PHP 8 对未定义键的访问会直接抛警告,取末尾元素前先判空,线上能少一批告警。