是否有一个函数将PHP数组的副本复制到另一个?

vfc*_*sts 499 php arrays copy

是否有一个函数将PHP数组的副本复制到另一个?

我已经烧了几次试图复制PHP数组.我想将对象内定义的数组复制到其外部的全局.

tro*_*skn 890

在PHP中,数组是通过复制分配的,而对象是通过引用分配的.这意味着:

$a = array();
$b = $a;
$b['foo'] = 42;
var_dump($a);
Run Code Online (Sandbox Code Playgroud)

将产量:

array(0) {
}
Run Code Online (Sandbox Code Playgroud)

鉴于:

$a = new StdClass();
$b = $a;
$b->foo = 42;
var_dump($a);
Run Code Online (Sandbox Code Playgroud)

产量:

object(stdClass)#1 (1) {
  ["foo"]=>
  int(42)
}
Run Code Online (Sandbox Code Playgroud)

您可能会对复杂性感到困惑,例如ArrayObject,这个对象的行为与数组完全相同.然而,作为一个对象,它具有引用语义.

编辑:@AndrewLarsson在下面的评论中提出了一点.PHP有一个称为"引用"的特殊功能.它们有点类似于C/C++等语言中的指针,但并不完全相同.如果您的数组包含引用,那么当数组本身通过副本传递时,引用仍将解析为原始目标.这当然通常是理想的行为,但我认为值得一提.

  • 你没有回答这个问题.你只解释了这个问题.对于OP来说,最有可能的是他正在寻找的东西.然而,对于我(以及其他人)来说,差不多四年后来到这里遇到类似的问题,我仍然没有很好的方法来克隆数组而不修改原始数组(包括内部指针).我想是时候问我自己的问题了. (93认同)
  • @AndrewLarsson但PHP默认情况下这样做 - 这就是它的要点.但是,引用仍未解析,因此如果您需要,则必须以递归方式遍历数组并构建新数组 - 同样,如果源数组包含对象,并且您希望克隆这些数组,则必须手动执行此操作.还要记住,PHP中的引用与*中的指针不相同.在不了解您的情况的情况下,我可以建议在第一种情况下使用引用数组很奇怪,特别是如果您不是意图把它们当作参考?用例是什么? (25认同)
  • 一如既往`php`向我们展示**最不期望的结果**,因为这个解决方案**并不总是有效**.`$ A =阵列(); $ B = $ A; $ B [ "X"] = 0; $ C = $ B; $ B [ "X"] = 1; echo gettype($ b),$ c ["x"];`打印`array0`而`$ a = $ GLOBALS; $ B = $ A; $ B [ "X"] = 0; $ C = $ B; $ B [ "X"] = 1; echo gettype($ b),$ c ["x"];`print`array1`.显然,一些数组是通过引用复制的. (8认同)
  • 但是什么时候不希望行为呢?问题是如何制作*深*副本.这显然是不可取的.你的答案并不比:`$ copy = $ original;`.如果数组元素是引用,则不起作用. (3认同)
  • @troelskn 我添加了这个问题的答案,并解决了我的问题:http://stackoverflow.com/a/17729234/1134804 (2认同)

sli*_*kts 178

PHP将默认复制该数组.PHP中的引用必须是明确的.

$a = array(1,2);
$b = $a; // $b will be a different array
$c = &$a; // $c will be a reference to $a
Run Code Online (Sandbox Code Playgroud)

  • @robsch - 在程序逻辑级别,复制数组.但是在内存中,它实际上不会被复制,直到它被修改 - 因为PHP使用所有类型的写时复制语义.http://stackoverflow.com/questions/11074970/will-copy-on-write-prevent-data-duplication-on-arrays (9认同)
  • 请注意,对于嵌套数组,情况并非如此,它们是引用,因此您最终会遇到混乱 (4认同)
  • @CoreyKnight 很高兴知道。这次真是万分感谢。 (2认同)

And*_*son 41

如果您有一个包含对象的数组,则需要复制该数组而不触及其内部指针,并且需要克隆所有对象(这样当您对复制的对象进行更改时,您不会修改原始数据数组),使用这个.

不接触数组内部指针的技巧是确保你正在处理数组的副本,而不是原始数组(或对它的引用),所以使用函数参数将完成工作(因此,这是一个接收数组的函数.

请注意,如果您还希望克隆其属性,则仍需要在对象上实现__clone().

此函数适用于任何类型的数组(包括混合类型).

function array_clone($array) {
    return array_map(function($element) {
        return ((is_array($element))
            ? array_clone($element)
            : ((is_object($element))
                ? clone $element
                : $element
            )
        );
    }, $array);
}
Run Code Online (Sandbox Code Playgroud)

  • 使用`__FUNCTION__`非常棒. (6认同)
  • @troelskn我通过添加一些递归来修复它.此函数现在适用于任何类型的数组,包括混合类型.它也适用于简单数组,因此它不再本地化.它基本上是一个通用的阵列克隆机器.你仍然需要在你的对象中定义__clone()函数,如果它们很深,但这超出了这个函数的"范围"(对不好的双关语抱歉). (4认同)
  • 我坚信这是这个问题的实际答案,我看到实际深度复制包含对象的数组的唯一方法. (2认同)

cha*_*aos 28

当你这样做

$array_x = $array_y;
Run Code Online (Sandbox Code Playgroud)

PHP复制数组,所以我不确定你将如何被烧毁.对于你的情况,

global $foo;
$foo = $obj->bar;
Run Code Online (Sandbox Code Playgroud)

应该工作正常.

为了被烧毁,我认为你要么必须使用引用,要么希望克隆数组中的对象.

  • +1为此:"或期望克隆数组中的对象" (12认同)

小智 18

array_merge() 是一个可以在PHP中将一个数组复制到另一个数组的函数.

  • 是的,但键将被修改,引用:*输入数组中带有数字键的值将使用从结果数组中的零开始的递增键重新编号.* (4认同)

Mat*_*sse 15

简单并使深层复制打破所有链接

$new=unserialize(serialize($old));
Run Code Online (Sandbox Code Playgroud)

  • 通常它工作正常但在某些情况下它可能会抛出异常,因为并非所有变量都是可序列化的(例如闭包和数据库连接). (4认同)

chr*_*cpn 11

如果阵列中只有基本类型,则可以执行以下操作:

$copy = json_decode( json_encode($array), true);
Run Code Online (Sandbox Code Playgroud)

您不需要手动更新引用
我知道它不适用于所有人,但它对我有用

  • +1这是一个非常糟糕的事情,但在技术上是正确和聪明的.如果我在代码中看到这个,我会面对手掌,但我忍不住喜欢它. (4认同)

Put*_*San 11

PHP> = 5.3简单而整洁

array_replace

array_replace_recursive(或$cloned = array_replace([], $YOUR_ARRAY);).对我来说是最干净的方式,就像Object.assign来自JavaScript.

$original = [ 'foo' => 'bar', 'fiz' => 'baz' ];

$cloned = array_replace([], $original);
$clonedWithReassignment = array_replace([], $original, ['foo' => 'changed']);
$clonedWithNewValues = array_replace([], $original, ['add' => 'new']);

$original['new'] = 'val';
Run Code Online (Sandbox Code Playgroud)

会导致

// original: 
{"foo":"bar","fiz":"baz","new":"val"}
// cloned:   
{"foo":"bar","fiz":"baz"}
// cloned with reassignment:
{"foo":"changed","fiz":"baz"}
// cloned with new values:
{"foo":"bar","fiz":"baz","add":"new"}
Run Code Online (Sandbox Code Playgroud)

  • 怎么样 [`array_slice($arr, 0)`](http://php.net/manual/en/function.array-slice.php) 或者当你不关心键时,[`array_values($arr )`](http://php.net/manual/en/function.array-values.php)?我认为它们可能比在数组中搜索更快。此外,在 javascript 中,使用 `Array.slice()` 来克隆数组非常流行。 (2认同)

Hus*_*ard 8

我发现最安全和最便宜的方法是:

<?php 
$b = array_values($a);
Run Code Online (Sandbox Code Playgroud)

这也有利于重新索引数组。

这在关联数组(哈希)上不会按预期工作,但在之前的大多数答案中都不会。


bes*_*rld 7

我很久以前就知道这一点,但这对我有用..

$copied_array = array_slice($original_array,0,count($original_array));
Run Code Online (Sandbox Code Playgroud)

  • 您不需要计数: `$copied_array = array_slice($original_array, 0);` 就足够了。 (3认同)