前几天我遇到了这个看似非常简单的问题如何在不引用 $array1 的情况下更改 $array2 中的值?然而,我对它的研究越多,它似乎就越奇怪,这确实按预期运行。在此之后,我开始研究从以下输出生成的操作码。
$array1 = array(2, 10);
$x = &$array1[1];
$array2 = $array1;
$array2[1] = 22;
echo $array1[1]; // Outputs 22
这对我来说似乎很疯狂,因为 array2 应该只是 array1 的副本,并且一个数组发生的任何事情都不应该影响另一个数组的内容。当然,如果您注释掉第二行,最后一行将像预期的那样回显 10。
看得更远,我可以看到一个很酷的网站,它向我展示了 PHP 使用 Vulcan Logic Dumper 生成的操作码。这是上述代码生成的操作码。
Finding entry points
Branch analysis from position: 0
Return found
filename: /in/qO86H
function name: (null)
number of ops: 11
compiled vars: !0 = $array1, !1 = $x, !2 = $array2
line # * op fetch ext return operands
---------------------------------------------------------------------------------
3 0 > INIT_ARRAY ~0 2
1 ADD_ARRAY_ELEMENT ~0 10
2 ASSIGN !0, ~0
4 3 FETCH_DIM_W $2 !0, 1
4 ASSIGN_REF !1, $2
5 5 ASSIGN !2, !0
6 6 ASSIGN_DIM !2, 1
7 OP_DATA 22, $6
8 8 FETCH_DIM_R $7 !0, 1
9 ECHO $7
10 > RETURN 1
这些操作码在这里没有很好地记录http://php.net/manual/en/internals2.opcodes.php但我相信在英语中操作码正在执行以下操作。按行...可能对我来说比其他任何人都重要。
- 第 3 行:我们用它的第一个值初始化数组,然后在将它分配给 $array1 之前给它加 10。
- 第 4 行:获取只写?数组中的值并通过引用 $x 来分配它。
- 第 5 行:将 $array1 设置为 $array2。
- 第 6 行:获取 1 的数组索引。我猜 od_data 将其设置为 22,尽管 $6 从未返回。OD_DATA 绝对没有文档,并且在我看过的任何地方都没有列为操作码。
- 第 8 行:从 $array1 的索引 1 中获取一个只读值并将其回显。
即使通过操作码工作,我也不确定这是哪里出错了。我有一种感觉,缺乏关于操作码的文档,而且我没有使用它们的经验,这可能使我无法弄清楚哪里出了问题。
编辑1:
正如 Mike 在第一个评论数组中指出的那样,复制数组时会保留引用状态。这里可以看到文档以及它链接到http://php.net/manual/en/language.types.array.php#104064的数组文章中的一个位置。这很有趣,不被视为警告。如果这是真的,那么令我惊讶的是,没有像您期望的那样保留此代码的参考状态。
$array1 = array(2, 10);
$x = &$array1;
$array2 = $array1;
$array2[1] = 22;
echo $array1[1]; // Output is 10
因此,似乎只有当您尝试通过引用分配单个元素时才会发生这种情况,从而使此功能更加混乱。
为什么php只在单独分配数组索引时保留它们的状态?
编辑2:
我今天使用 HHVM 进行了一些测试,HHVM 以您认为的方式处理了第一个代码片段。我喜欢 PHP,但 HHVM 比 Zend 引擎看起来越来越好。