SplStack和SplQueue基于双向链表,push/pop/enqueue/dequeue均为O(1),而数组模拟队列时array_shift为O(n),栈场景二者性能相当,队列场景SPL显著更优。

直接上手 SPL,别从“什么是迭代器”开始读文档。它不是理论课,是 PHP 里现成能替换掉你那些 array_push + array_shift + foreach 套路的工具箱——用错地方才需要重学。
什么时候该用 SplStack 而不是数组模拟栈
当你写 array_push($stack, $item) 然后 array_pop($stack),且频繁执行(比如解析嵌套表达式、回溯路径),就该换 SplStack。
-
SplStack是 C 实现的双向链表,push/pop/top全是 O(1),而数组的array_pop虽快,但array_unshift或中间插入会触发整块内存重排 - 它实现了
Countable和Iterator,可直接count($stack)和foreach ($stack as $v),不用再count($arr)或array_values($arr) - 空栈调用
pop()会抛RuntimeException,不是静默返回null或false—— 这是好事,逼你显式处理边界,而不是靠if (!empty($arr))补丁式防御
SplQueue 的 enqueue/dequeue 和数组的差异在哪
别用 array_push + array_shift 模拟队列:后者时间复杂度是 O(n),每次删头都要搬动后面所有元素。
-
SplQueue的enqueue()和dequeue()都是 O(1),底层不挪数据,只改指针 - 它支持
ArrayAccess,所以能写$queue[0]查看队首(但不推荐,语义不清;用bottom()更安全) - 注意:它不支持随机访问,
$queue[5]会报RuntimeException,不是像数组那样返回NULL - 如果业务需要“查看但不取出”,
SplQueue没有内置peek(),得自己封装:current($queue->getIterator())或先dequeue再enqueue回去(不推荐)
为什么 ArrayObject 比普通数组更适合配置或 DTO 场景
当你把配置项、API 返回结构、表单数据当成“数据容器”而非“计算载体”时,ArrayObject 就比原生数组更可控。
立即学习“PHP免费学习笔记(深入)”;
- 它能被序列化(
serialize()),原生数组也能,但ArrayObject可以绑定自定义序列化逻辑(通过实现Serializable接口) - 支持对象式访问:
$obj->name或$obj['name'],避免$arr['name'] ?? null这种防御式写法泛滥 - 可挂载迭代器行为:传入
ArrayObject::STD_PROP_LIST或ArrayObject::ARRAY_AS_PROPS控制属性/键值访问权限,防止意外写入非法字段 - 它不是数组的“升级版”,而是“约束版”:不能用
+合并,不能用array_merge,强制你走append()/offsetSet(),这对数据一致性是加分项
SplFixedArray 真的比普通数组快?什么情况下值得切
只在明确知道长度且极少变动时才考虑它,否则就是给自己加维护成本。
- 它在内存中是连续分配的,索引访问是纯指针偏移,比 PHP 数组(哈希表实现)的键查找快 2–3 倍,尤其在循环中
$arr[$i]百万次以上时可见差距 - 必须提前指定大小:
new SplFixedArray(1000),之后不能push,不能resize,越界写入直接 fatal error - 不支持字符串键,不支持
foreach直接遍历(需用getSize()+offsetGet($i)手动循环) - 它不实现
ArrayAccess默认接口,要手动启用:new SplFixedArray(1000)->setFlags(SplFixedArray::USE_KEY_AS_INDEX),否则offsetGet会失败
真正容易被忽略的点是:SPL 类大多为 final,不能继承。想扩展功能,得用组合(wrapper class)或装饰器模式,而不是习惯性写 class MyStack extends SplStack —— 那会直接报错。



















