PHP 数组引用


PHP array reference

我有这个php代码

$a = array('one');
$b[0] = &$a[0];
$c = $a;
$b[0] = 'three';
$a = array('two');
var_dump($a); echo '<br/>';
var_dump($b); echo '<br/>';
var_dump($c); echo '<br/>';

输出此 ->

array(1) { [0]=> string(3) "two" }
array(1) { [0]=> &string(5) "three" }
array(1) { [0]=> &string(5) "three" }

$b 和 $a 指向相同的值,但$c不应指向相同的值,它应该有自己的值副本。然后,当我将$b的值更改为 3 时,我不明白为什么$c的值也会发生变化。我该如何防止这种情况?另外,当我将$a的值更改为"二"时,为什么$b不也更改为"二"?

提前谢谢。

你的问题是:

$b[0] = &$a[0];

这引用了数组的第一个元素。从var_dump()输出&string(5)可以看出。

所以$b不引用整个数组,只引用第一个元素。

要引用整个数组,您需要执行以下操作:

$b = &$a;

这样做可以按预期工作:

// $a
array(1) {
  [0]=>
  string(3) "two"
}
// $b
array(1) {
  [0]=>
  string(3) "two"
}
// $c
array(1) {
  [0]=>
  string(3) "one"
}

阅读更多关于 PHP 中的数组。

这是一个分步说明:

$a = array('one');
$b[0] = &$a[0];

$b现在是一个数组,它的第一个元素引用$a的第一个元素。在符号表中,$b[0]$a[0]指向相同的基础 zval。

$c = $a;

$c引用现在$a,但尚未创建副本(写入语义上的复制(。它看起来很像这样:

$c ----/----> $a             $b
(0: 'one')    0: 'one' <---- 0: 'one'

下一条语句:

$b[0] = 'three';

这也更新$a[0],进而更新$c[0],因为$a本身不会改变。它现在看起来像;

$c ----/----> $a               $b
(0: 'three')  0: 'three' <---- 0: 'three'

下一条声明:

$a = array('two');

断开$a$c的连接,断开$a[0]$b[0]的连接。

$c          $a        $b
0: 'three'  0: 'two'  0: 'three'

预防

为了防止这种行为,你需要引用整个数组,而不仅仅是一个元素:

$b = &$a;

通过这样做,$b$a现在引用相同的 zval(数组本身(,因此所做的任何更改都会将其与 $c 断开连接。

不过,我会考虑该语言的这些边缘情况,如果您不需要,我建议您不要使用引用。

了解按引用与值分配时正在执行的操作非常重要。让我们一行一行地进行。

$a = array('one');

$a指向 M1,在 M1 中我们有一个包含 1 个条目的数组,我们称之为 M1-A1。

$b[0] = &$a[0];

现在我们要做的是将$b[0]指向M1-A1。请记住,$a[0] 也指向 M1-A1,因此两者都指向内存的这一特定部分。请记住,$b本身有自己的内存位置 M2,但在 M2 中我们指向 M1-A1(即 M2-A1 指向 M1-A1(。

$c = $a;

由于我们不是通过引用分配的,我们得到的是一个新的内存位置,我们称之为 M3,但在 M3 中有一个数组,第一个条目仍然指向 M1-A1。

所以现在我们有 M1、M2

、M3,在 M2 和 M3 中有一个指向 M1-A1 的数组条目。

$b[0] = 'three';

由于$b[0]实际上指向M1-A1,我们实际上正在更改M1-A1记忆点的值。因此,任何引用M1-A1位置的东西也会看到这个值的变化。

$a = array('two');

此时,我们正在完全更改$a的内存位置。最初是 M1,现在我们正在创建一个新的内存位置 M4。没有其他东西指向 M4,M4-A1 也不指向 M1-A1。

因此,当我们进行 var 转储时,我们会得到您提到的值。

我可能使这更加混乱,但尝试将其画在纸上,它会很清楚。了解所有内容都存储在内存中,变量仅指向内存位置。一旦你理解了这个原则,一切都会到位。

它们都引用内存中的同一数组对象