让我们假设您使用嵌套的PHP数组创建一个复杂的数据结构,如下所示:
$a1 = array(
'b' => array('foo' => 1),
'c' => array('bar' => 1)
);
想象一下,数组要更加嵌套,包含更多元素和更长,更有意义的名称。
如果需要经常访问$ a1的子结构,对于读写,可能会想要创建一个"别名"像这样:
$b = &$a1['b'];
然而,这会导致大量混乱,因为"任务"实际上改变了$ a1 。
我认为许多缺乏经验的PHP开发人员(比如我)会认为$ b是在分配后对$ a1 [' b']的引用。真正发生的是 $ b和$ a1 [' b']变成了对元素array('foo' => 1)
的引用,带来意想不到的后果。我发现这非常不直观。
我们假设您需要保留$ a1,但是您还需要$ a1的副本,让我们调用副本$ a2,并更改$ a2的一些元素:
$a2 = $a1; // Copy $a1 to $a2
$a2['b']['foo'] = 2; // GOTCHA! This will change $a1['b']['foo'] as well!
$a2['c']['bar'] = 2; // This will not change $a1['c']['bar'] however
因为我们之前创建了对$ a1 [' b']的引用,所以该元素将通过引用分配,而$ a1的其余部分将按值复制。这花了我几个小时才弄明白。
var_dump($a1);
var_dump($a2);
将输出
array (size=2)
'b' => &
array (size=1)
'foo' => int 2
'c' =>
array (size=1)
'bar' => int 1
array (size=2)
'b' => &
array (size=1)
'foo' => int 2
'c' =>
array (size=1)
'bar' => int 2
请注意&在''之后元素,表明它是一个参考。并且$ a1 [' b'] [' foo']的价值从1更改为2.
当可能对源数组中的元素进行引用时,是否有一种非常简单的按值复制数组的方法?
或换句话说:有没有办法确保在将$ a1复制到$ a2时,$ a1 [' b']按值复制,以便更改$ a2 [' b']不会破坏$ a1 [' b']?
我发现你可以这样做:
unset($b); // Remove reference to $a1['b']
$a2 = $a1; // Now all of $a1 will be copied to $a2 by value
$b = &$a1['b']; // Recreate reference
当然,如果有更多对$ a1 [' b']或$ a1的其他元素的引用,则需要将它们全部取消。我希望有一种更聪明的方式,例如"反向"到=& (通过引用赋值)运算符或函数以按值递归复制深层嵌套的关联数组。即使创建了对您不了解的数组元素的引用,也会始终有效。
这是我到目前为止找到的最接近解决方案的方法。它似乎有效,但它不是"漂亮":
$a2 = json_decode(json_encode($a1), true);
我的问题与SO上的其他几个问题有关。但是,我还没有找到我的具体问题的答案。甚至是一个答案,可以直观地理解这种奇怪和意外行为背后的机制。例如,Array reference confusion in PHP的答案引用了PHP手册,其中说:
但请注意,数组内部的引用是可能的 危险的。使用a执行正常(不是通过引用)赋值 右侧的参考不会将左侧变为a 引用,但数组内的引用保留在这些正常情况下 分配。
我已阅读本手册的部分,但我发现它无益。它没有提供更深入的理解,也没有解释如何安全地使用对数组元素的引用。 PHP手册页What References Do上的一条评论提到了这种奇怪的行为,但没有提出如何处理它的建议。
这只是其中一个记录不清的问题"怪癖"您必须学会使用的PHP?或者对这个主题有一些更深刻的理解会有所帮助,在这种情况下我最有可能找到启示?
答案 0 :(得分:2)
你做了很多研究。
无法理解究竟是什么问题?
我想我找到了另一个非常接近你的json编码解码变体的解决方案:
有没有办法确保在将$ a1复制到$ a2时,$ a1 [' b']按值复制,以便更改$ a2 [' b&# 39;]不会破坏$ a1 [' b']?
请检查:
$a1 = array(
'b' => array('foo' => 1),
'c' => array('bar' => 1)
);
$b = &$a1['b'];
$a2 = unserialize(serialize($a1)); // Copy $a1 to $a2
$a2['b']['foo'] = 2; // GOTCHA!
$a2['c']['bar'] = 2; //
var_dump($a1);
var_dump($a2);
为我输出:
array(2) {
["b"]=>
&array(1) {
["foo"]=>
int(1)
}
["c"]=>
array(1) {
["bar"]=>
int(1)
}
}
array(2) {
["b"]=>
array(1) {
["foo"]=>
int(2)
}
["c"]=>
array(1) {
["bar"]=>
int(2)
}
}
是你要求的吗?
顺便说一下,这里有一个比较json_encode和序列化的链接,这可能会有所帮助
Preferred method to store PHP arrays (json_encode vs serialize)