PHP数组复制:简单赋值还是克隆?

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

PHP中的深拷贝数组:神话与现实

\n\n

想象一下这个场景:您正在编写一个处理数据库数据的脚本。您获取了一个用户数组,对其进行了一些操作,然后突然发现原始数据发生了变化。熟悉吗?如果您使用PHP,这个问题甚至可能让经验丰富的开发者措手不及。

\n\n

Stack Overflow上的问题“Is there a function to make a copy of a PHP array to another?” 获得了数万次浏览。这并非偶然。乍一看,在PHP中复制数组似乎是一项简单的任务。但魔鬼,一如既往,隐藏在细节之中。

\n\n

在本文中,我们将探讨PHP中复制数组的所有可能方法:从简单的赋值到处理多维结构。您将了解PHP何时创建真正的副本,何时仅创建数据的引用。我们开始吧!

\n\n

直接赋值:第一个惊喜

\n\n

最直观的方法就是直接将数组赋值给另一个变量:

\n\n
$original = ['apple', 'banana', 'cherry'];\n$copy = $original;\n$copy[0] = 'mango';\n\nprint_r($original);\n// Array ( [0] => apple [1] => banana [2] => cherry )\nprint_r($copy);\n// Array ( [0] => mango [1] => banana [2] => cherry )
\n\n

令人惊讶的是,这居然有效!在PHP中,数组是值类型,而不是引用类型。当您将一个数组赋值给另一个变量时,PHP会创建一个带有写时复制机制的浅拷贝。

\n\n

简单来说:只要您不修改任何一个数组,它们就指向内存中的同一份数据。一旦您尝试修改其中一个变量中的元素,PHP就会分配新的内存并复制数据。这非常高效,无需额外操作。

\n\n

结论:对于简单的一维数组,直接赋值就是完整的复制。

\n\n

陷阱:数组中的对象

\n\n

现在想象一下,数组中包含对象:

\n\n
class User {\n    public $name;\n    public function __construct($name) {\n        $this->name = $name;\n    }\n}\n\n$original = [new User('Alice'), new User('Bob')];\n$copy = $original;\n$copy[0]->name = 'Charlie';\n\nprint_r($original[0]->name); // Charlie
\n\n

惊喜来了!浅拷贝复制的是对象的引用,而不是对象本身。修改副本中的对象,也会改变原始对象。对于对象,需要采用不同的方法。

\n\n

array_merge()函数:不明显的细微差别

\n\n

经常有人建议使用array_merge()来复制数组:

\n\n
$original = [1, 2, 3];\n$copy = array_merge([], $original);\n$copy[0] = 100;\n\nprint_r($original); // [1, 2, 3]
\n\n

是的,这有效。但有一个重要的细微差别:array_merge()会重置数字键并从零开始重新编号。如果您的键是字符串,则没有问题。但如果是数字键,请准备好迎接惊喜:

\n\n
$original = ['a' => 1, 2 => 'two', 5 => 'five'];\n$copy = array_merge([], $original);\n\nprint_r($copy);\n// Array ( [a] => 1 [0] => two [1] => five )
\n\n

看到了吗?键2和5变成了0和1。如果键的顺序很重要,这可能会破坏逻辑。

\n\n

结论:array_merge()仅适用于复制具有字符串键的数组,或者当重新索引不会造成问题时。

\n\n

使用循环复制:手动控制

\n\n

最可靠但也是最冗长的方法是遍历数组:

\n\n
$original = ['x' => 10, 'y' => 20];\n$copy = [];\n\nforeach ($original as $key => $value) {\n    $copy[$key] = $value;\n}\n\n$copy['x'] = 100;\nprint_r($original['x']); // 10
\n\n

对于简单数组来说,这有些冗余。但如果您需要进行深拷贝,那么没有递

博客

书籍推荐