PHP中的数组是非常常用的数据结构,很多场景下我们需要对数组进行复制操作,比如把一个数组赋值给另一个变量。不少开发者会担心直接复制数组会导致内存占用翻倍,实际上PHP的数组复制行为有特殊的机制,并不会在赋值时立刻复制整个数组内容。

PHP数组的写时复制机制
PHP的变量赋值默认采用的是写时复制(Copy On Write,简称COW)策略,数组作为变量的一种,同样遵循这个规则。当我们把一个数组赋值给另一个变量时,两个变量会指向同一个内存地址的数组结构,此时并不会分配新的内存空间。
只有当其中一个变量对数组内容进行修改时,PHP才会真正复制一份数组数据,给修改的变量分配新的内存,这就是写时复制的核心逻辑。这个机制可以有效减少不必要的内存开销,提升程序的运行效率。
不同复制场景的内存测试
我们可以通过memory_get_usage()函数来测试不同操作下的内存占用情况,下面的代码示例会直观展示数组复制的内存变化。
<?php // 初始内存 $startMemory = memory_get_usage(); // 创建一个包含10000个元素的数组 $arr1 = range(1, 10000); $memoryAfterCreate = memory_get_usage(); echo "创建数组后内存占用:" . ($memoryAfterCreate - $startMemory) . " bytes" . PHP_EOL; // 直接赋值复制数组,此时触发写时复制,不会新增内存 $arr2 = $arr1; $memoryAfterAssign = memory_get_usage(); echo "赋值复制后内存占用:" . ($memoryAfterAssign - $startMemory) . " bytes" . PHP_EOL; // 修改复制后的数组,此时会触发真正的数组复制,内存会增加 $arr2[0] = 999; $memoryAfterModify = memory_get_usage(); echo "修改复制数组后内存占用:" . ($memoryAfterModify - $startMemory) . " bytes" . PHP_EOL; // 使用array_copy函数复制数组,同样遵循写时复制吗?实际array_copy是内部复制,会直接分配新内存 $arr3 = array_copy($arr1); $memoryAfterArrayCopy = memory_get_usage(); echo "使用array_copy复制后内存占用:" . ($memoryAfterArrayCopy - $startMemory) . " bytes" . PHP_EOL; ?>
运行上面的代码,你会发现赋值复制后内存没有明显增长,而修改复制数组或者使用array_copy函数后,内存会明显上升,这和写时复制的机制完全吻合。
引用赋值对数组复制的影响
如果我们使用引用赋值的方式复制数组,情况会有所不同。引用赋值会让两个变量始终指向同一个内存地址,无论是否修改数组,都不会触发写时复制。
<?php $arrA = [1, 2, 3, 4, 5]; // 引用赋值 $arrB = &$arrA; // 此时修改$arrB会直接修改$arrA指向的数组,不会复制 $arrB[0] = 100; var_dump($arrA); // 输出[100,2,3,4,5] var_dump($arrB); // 输出[100,2,3,4,5] ?>
这种场景下,两个变量完全绑定,不存在独立复制的情况,内存占用也不会因为赋值操作增加,但是修改任意一个变量都会影响另一个,使用时需要注意副作用。
数组复制的常见误区
- 误区一:直接赋值数组会立刻复制全部内容。实际上只有触发写操作时才会复制,普通赋值只是增加引用计数。
- 误区二:所有数组复制函数都遵循写时复制。部分内置函数比如
array_merge、array_slice返回的是新的数组,会直接分配新内存,不属于写时复制的范畴。 - 误区三:引用赋值更省内存。引用赋值虽然不会复制数组,但是会导致变量耦合,容易引发逻辑错误,需要根据场景选择使用。
实际开发中的优化建议
如果只是需要读取数组内容,不需要修改,直接赋值即可,不需要额外做复制操作,利用写时复制机制可以减少内存开销。如果确定需要独立修改数组的副本,再考虑使用复制操作或者相关函数。另外要注意避免在循环中频繁复制大数组,尽量提前处理好数组副本,减少不必要的内存波动。
PHP数组复制内存占用copy_on_write修改时间:2026-07-20 03:33:26