你能用值显式复制包含“引用”元素的PHP数组吗?
关于
PHP数组元素的引用的背景
假设您使用嵌套的PHP数组创建一个复杂的数据结构,如下所示: $a1 = array( 'b' => array('foo' => 1),'c' => array('bar' => 1) ); 想象一下,数组要更深层次嵌套,具有更多元素和更长,更有意义的名称. 如果需要经常访问$a1的子结构,对于读写,可能会想要创建这样的“别名”: $b = &$a1['b']; 然而,由于“任务”实际上改变了$a1,这导致了巨大的混乱. 我认为许多缺乏经验的PHP开发人员(比如我)会认为$b是在分配后对$a1 [‘b’]的引用.真正发生的是$b AND $a1 [‘b’]变成对元素数组的引用(‘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 请注意&在’b’元素之后,表明它是一个参考.并且$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手册,其中说:
我已经阅读了手册的部分,我发现它没有用.它没有提供更深入的理解,也没有解释如何安全地使用对数组元素的引用. PHP手册页面What References Do上的一条评论提到了奇怪的行为,但没有提出如何处理它的建议. 这只是PHP中缺乏文档记录的“怪癖”中的一个,你只需要学习如何使用它?或者对这个主题有一些更深刻的理解会有所帮助,在这种情况下我最有可能找到启示?
你做了很多研究.
只是无法理解究竟是什么问题? 我想我找到了另一个非常接近你的json编码解码变体的解决方案: 有没有办法确保在复制$a1到$a2时,按值复制$a1 [‘b’]以便更改$a2 [‘b’]不会破坏$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) (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |