你能用值显式复制包含"引用"元素的PHP数组吗?

Tom*_*und 7 php arrays reference

关于PHP数组元素的引用的背景

假设您使用嵌套的PHP数组创建一个复杂的数据结构,如下所示:

$a1 = array(
    'b' => array('foo' => 1),
    'c' => array('bar' => 1)
);
Run Code Online (Sandbox Code Playgroud)

想象一下,数组要更加嵌套,具有更多元素和更长,更有意义的名称.

如果需要经常访问$ a1的子结构,对于读写,可能会想要创建这样的"别名":

$b = &$a1['b'];
Run Code Online (Sandbox Code Playgroud)

然而,由于"任务"实际上改变了$ a1,这导致了巨大的混乱.

我认为许多缺乏经验的PHP开发人员(比如我)会认为$ b是在分配后对$ a1 ['b']的引用.真正发生的是$ b AND $ 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
Run Code Online (Sandbox Code Playgroud)

因为我们之前创建了对$ a1 ['b']的引用,所以该元素将通过引用分配,而$ a1的其余部分按值复制.这花了我几个小时才弄明白.

var_dump($a1);
var_dump($a2);
Run Code Online (Sandbox Code Playgroud)

会输出

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
Run Code Online (Sandbox Code Playgroud)

请注意'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
Run Code Online (Sandbox Code Playgroud)

当然,如果有更多对$ a1 ['b']或$ a1的其他元素的引用,则需要将它们全部取消.我希望有一种更聪明的方法,例如=&(通过引用赋值)运算符的"逆"或者按值递归复制深度嵌套的关联数组的函数.即使存在对您不知道的数组元素创建的引用,也会始终有效的东西.

这是我到目前为止找到的解决方案最接近的.它似乎工作,但它不"漂亮":

$a2 = json_decode(json_encode($a1), true);
Run Code Online (Sandbox Code Playgroud)

研究完成了

我的问题与SO上的其他几个问题有关.但是,我还没有找到我的具体问题的答案.甚至是一个答案,可以直观地理解这种奇怪和意外行为背后的机制.例如,PHP中数组引用混淆的答案引用了PHP手册,其中说:

但请注意,数组内部的引用可能存在危险.使用右侧的引用执行正常(非引用)赋值不会将左侧转换为引用,但是在这些正常赋值中保留数组内的引用.

我已经阅读了手册的部分,我发现它没有用.它没有提供更深入的理解,也没有解释如何安全地使用对数组元素的引用.关于PHP手册页的一条评论什么参考文献提到了奇怪的行为,但没有提出如何处理它的建议.

这只是PHP中缺乏文档记录的"怪癖"中的一个,你只需要学习如何使用它?或者对这个主题有一些更深刻的理解会有所帮助,在这种情况下我最有可能找到启示?

Ale*_*lex 2

你做了很好的研究。

只是无法理解确切的问题是什么?

我想我找到了另一种与您的 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);
Run Code Online (Sandbox Code Playgroud)

为我输出:

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)
  }
}
Run Code Online (Sandbox Code Playgroud)

这是你要求的吗?

顺便说一句,这里有一个比较 json_encode 与序列化的链接,它可能会有所帮助

存储 PHP 数组的首选方法(json_encode 与序列化)


归档时间:

查看次数:

175 次

最近记录:

10 年 前