复制对象的值而不复制引用

问题描述 投票:0回答:7

我有以下代码:

$data['x'] = $this->x->getResults();  

$data['y'] = $data['x'];

//some code here to modify $data['y']
//this causes (undesirably) $data['x] to be modified as well

我想既然 $data 的所有元素本身都是引用,修改

$data['y']
也会修改
$data['x']
这不是我想要的。我希望
$data['x']
保持不变。有什么方法可以取消引用此处的元素,以便我可以按值复制元素吗?

更新:

$this->x->getResults();
返回一个对象数组。所以我可以做类似的事情:
$data['x'][0]->date_create
...

更新: 我最近尝试克隆数组看起来像这样:

$data['x'] = $this->x->getResults();     
$data['y'] = $data['y'];
foreach($data['x'] as $key=>$row) {
    $data['y'][$key]->some_attr = clone $row->some_attr;
}

我离这里还远吗?我不断收到“在非对象上调用 __clone 方法”错误。从阅读响应来看,我最好的选择似乎是迭代每个元素并克隆它(这就是我试图用该代码做的事情..)。

php object reference clone
7个回答
11
投票

您可以利用 PHP 将取消引用函数调用结果的事实。

这是我编写的一些示例代码:

$x = 'x';
$y = 'y';
$arr = array(&$x,&$y);
print_r($arr);

echo "<br/>";
$arr2 = $arr;
$arr2[0] = 'zzz';
print_r($arr);
print_r($arr2);

echo "<br/>";
$arr2 = array_flip(array_flip($arr));
$arr2[0] = '123';
print_r($arr);
print_r($arr2);

结果如下所示:

数组 ( [0] => x [1] => y )
数组 ( [0] => zzz [1] => y ) 数组 ( [0] => zzz [1] => y )
数组 ( [0] => zzz [1] => y ) 数组 ( [0] => 123 [1] => y )

您可以看到,在将

array_flip()
分配给
$arr
期间使用
$arr2
的结果会导致对
$arr2
的后续更改有所不同,因为
array_flip()
调用会强制取消引用。

它看起来效率不是很高,但如果

$this->x->getResults()
返回一个数组,它可能对你有用:

$data['x'] = array_flip(array_flip($this->x->getResults()));
$data['y'] = $data['x'];

请参阅此(未答复)线程了解另一个示例。

如果返回数组中的所有内容都是对象,那么复制对象的唯一方法是使用

clone()
,并且您必须迭代
$data['x']
并将每个元素克隆到
$data['y']
中。

示例:

$data['x'] = $this->x->getResults();
$data['y'] = array();
foreach($data['x'] as $key => $obj) {
    $data['y'][$key] = clone $obj;
}

9
投票

array_merge()
可以接受任意数量的参数,甚至1个,然后生成一个新数组。所以只需执行以下操作:

$new_array = array_merge($existing_array);

7
投票
当数组值既不是字符串也不是整数时,

array_flip()
将不起作用。 不过,我找到了一个简单的解决方案:

$clonedArr = (array)clone(object)$arr;

这要归功于对象上的克隆属性。


3
投票

不简单。 了解克隆

但是!如果你的元素不是对象并且不是引用类型变量,那么你就没有问题。

参考类型示例:

$v=11;
$arr[]=&$v;

2
投票

如果您正在使用对象,您可能需要查看

clone
,以创建对象的 副本,而不是引用

这是一个非常简短的例子:

首先,对于数组,它按值工作:

$data['x'] = array(
    'a' => 'test',
    'b' => 'glop',
);
$data['y'] = $data['x'];
$data['y'][0] = 'Hello, world!';
var_dump($data['x']); // a => test : no problem with arrays

默认情况下,对于对象,它通过引用工作:

$data['x'] = (object)array(
    'a' => 'test',
    'b' => 'glop',
);
$data['y'] = $data['x'];
$data['y']->a = 'Hello, world!';
var_dump($data['x']); // a => Hello, world! : objects are by ref

但是,如果您克隆该对象,您将处理一个副本:
我想这就是你的情况?

$data['x'] = (object)array(
    'a' => 'test',
    'b' => 'glop',
);
$data['y'] = clone $data['x'];
$data['y']->a = 'Hello, world!';
var_dump($data['x']); // a => test : no ref, because of cloning

希望这有帮助,


1
投票

我刚刚发现,如果您只想从常量获取值数组(无引用)的副本,那么您可以编写:

$new_array =(数组)(对象)self::old_array;

不是OP问题的确切答案,但它帮助了我,也可能帮助其他人。


0
投票

您可以使用此函数来复制包含对象的多维数组。

<?php
function arrayCopy( array $array ) {
    $result = array();
    foreach( $array as $key => $val ) {
        if( is_array( $val ) ) {
            $result[$key] = arrayCopy( $val );
        } elseif ( is_object( $val ) ) {
            $result[$key] = clone $val;
        } else {
            $result[$key] = $val;
        }
    }
    return $result;
}
?>
© www.soinside.com 2019 - 2024. All rights reserved.