php数组拷贝采用写时复制机制,未修改时不分配新内存;显式引用(&)才共享内存,赋值(=)仍属逻辑独立,仅=&才真正绑定同一地址。

数组拷贝不是简单“复制还是不复制”的问题,关键看操作是否触发内存分离——PHP 中默认是写时复制(Copy-on-Write),表面像值传递,实则延迟分配;而显式引用(&)才真正共享同一块内存。
值传递:看似复制,实际按需分离
函数参数不加 & 时,PHP 不立即复制整个数组。只要你不修改它,$a 和函数内的形参共用同一份底层数据,零额外内存开销。
- 读取、遍历、isset() 等只读操作:不触发复制
- 修改元素(如 $arr[0] = 1)、添加键($arr[] = 2)、删除(unset($arr[0])):立刻复制副本,原数组不受影响
- 适合做数据查询、校验、生成新结构等不改动原始数组的场景
引用传递:用 & 显式绑定同一内存
函数定义和调用都带 &(如 function foo(&$arr)),意味着形参就是原数组的别名,所有操作直抵本体。
- 修改任意元素、增删键、重排顺序,外部变量立即可见变化
- 避免大数组反复复制,适合批量更新、递归构建、原地排序等任务
- 调用方必须清楚副作用:传进去的数组很可能被改掉
赋值语句里的陷阱:= 和 =& 完全不同
很多人以为 $b = $a 是“复制数组”,其实仍是写时复制机制保护下的逻辑独立;只有 $b =& $a 才让两者真正指向同一内存地址。
- $b = $a → 后续 $a[0] = 1 不影响 $b[0],反之亦然(除非都未修改,此时仍共享)
- $b =& $a → $a[0] = 1 后,$b[0] 立即变成 1;任一 unset 都同步生效
- 这个规则也适用于 foreach 中的变量:写成 foreach ($arr as &$v) 才能通过 $v 修改原数组
PHP 7+ 的优化与例外
新版 PHP 加强了引用跟踪,多数情况下更精准判断是否需要复制。但某些函数(如 func_get_args()、array_merge(...$arrays))仍可能强制创建副本,不能完全依赖“没改就不复制”的直觉。
- 调试时可用 xdebug_debug_zval('var_name') 查看 refcount 和 is_ref 标志
- 不确定时,对只读场景放心用值传递;对明确要改原数组的,坚持用 & 声明
- 避免混用:不要在同一个数组上交替使用 = 和 =&,容易引发难以追踪的状态混乱











