通过引用分配错误 [英] Assign by reference bug

查看:97
本文介绍了通过引用分配错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

前几天,我遇到了一个看似非常简单的问题如何在不引用$ array1的情况下更改$ array2中的值?之后,我开始研究从以下输出生成的操作码.

I came across this seemingly very simple question the other day How to changing value in $array2 without referring $array1? However the more i looked into it the more odd it seemed that this is indeed functioning as intended. After this I started looking into the opcodes that are generated from the output of the following.

$array1 = array(2, 10);
$x = &$array1[1];
$array2 = $array1;
$array2[1] = 22;

echo $array1[1]; // Outputs 22

在我看来这很疯狂,因为array2只能是array1的副本,并且发生在一个数组上的任何内容都不会影响另一个数组的内容.当然,如果您注释掉第二行,最后一行将像预期的那样回显10个.

This seems crazy to me since array2 should only be a copy of array1 and anything that happens to one array should not effect the contents of the other. Of course if you comment out the second line the final line will echo out 10 like expected.

再往前看,我可以找到一个很酷的网站,向我展示PHP使用Vulcan Logic Dumper生成的操作码.这是上面的代码生成的操作码.

Looking farther I could a cool site that shows me the opcodes that PHP produces using the Vulcan Logic Dumper. Here is the opcodes generated by the above code.

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 ,但我相信英语中的操作码可以做到以下几点.按行……对我来说可能比其他任何人都更重要.

These opcodes aren't documented great here http://php.net/manual/en/internals2.opcodes.php but I believe in English the opcodes are doing the following. By line... might be more for me than anyone else.

  1. 第3行:我们使用第一个值初始化数组,然后将其添加10,然后再将其分配给$ array1.
  2. 第4行:只写?数组中的值,并通过引用$ x对其进行分配.
  3. 第5行:将$ array1设置为$ array2.
  4. 第6行:获取1的数组索引.od_data我想将其设置为22,尽管从不返回$ 6. OD_DATA绝对没有任何文档,在我浏览过的任何地方都没有列出它为操作码.
  5. 第8行:从$ array1的索引1中获取一个只读值,并将其回显.

即使通过操作码进行操作,我也不知道这哪里出错了.我感到操作码缺少文档,而且我对操作码的使用经验不足,很可能使我无法弄清问题出在哪里.

Even working through the opcodes I am not sure where this is going wrong. I have a feeling the lack of documentation on the opcodes and my inexperience with working with them is likely keeping me from figuring out where this is going wrong.

正如Mike在第一个注释数组中指出的那样,在复制参考状态时会保留它们的状态.在这里可以看到文档以及链接到的数组文章中的位置. http://php.net/manual/en/language.types.array.php#104064 .这个足够有趣的现象不被视为警告.如果真是如此,令我感到惊讶的是,未按您期望的那样保留此代码的参考状态.

As pointed out by Mike in the first comment arrays reference status is preserved when they are copied. Here can be seen documentation along with a place in the array article it links to http://php.net/manual/en/language.types.array.php#104064. This funny enough is not considered a warning. What is surprising to me if this is true the reference status is not preserved for this code as you would expect.

$array1 = array(2, 10);
$x = &$array1;
$array2 = $array1;
$array2[1] = 22;

echo $array1[1]; // Output is 10

因此,似乎只有当您尝试通过引用分配单个元素时,此功能才会更加混乱.

So it seems this only happens when you try and assign single elements by reference making this functionality even more confusing.

为什么php仅在分别分配数组索引时才保留它们的状态?

Why does php only preserve the status of the arrays indexes when they are individually assigned?

我今天使用HHVM进行了一些测试,HHVM按照您的想法处理了代码的第一个片段.我喜欢PHP,但是HHVM在Zend Engine上看起来越来越好.

I did some testing using HHVM today and HHVM handles the first snip-it of code how you think it would. I love PHP but HHVM is looking better and better over the Zend Engine.

推荐答案

在PHP手册中对此进行了解释(即使您花费的时间要比找到它所花费的时间多),尤其是在 http://php.net/manual/en/language.types.array.php#104064

This is explained over at the PHP manual (even if you have to spend more time than you should have to in order to find it), specifically over at http://php.net/manual/en/language.types.array.php#104064

共享的"数据保持共享状态,初始分配仅充当别名.直到您开始使用...[] = ...之类的独立操作来处理数组时,解释器才开始将它们视为发散列表,并且即使共享的数据仍保持共享状态,因此您可以拥有两个共享的数组,第一个 n 元素,但随后的数据不同.

The "shared" data stays shared, with the initial assignment just acting as an alias. It's not until you start manipulating the arrays with independent operations like ...[] = ... that the intepreter starts to treat them as divergent lists, and even then the shared data stays shared so you can have two arrays with a shared first n elements but divergent subsequent data.

对于一个数组的真正按值复制"到另一个数组,您几乎最终会做类似的事情

For a true "copy by value" for one array to another, you pretty much end up doing something like

$arr2 = array();
foreach($arr1 as $val) {
  $arr2[] = $val;
}

$arr2 = array();
for($i=count($arr1)-1; $i>-1; $i--) {
  $arr2[$i] = $arr[$i];
}

(使用反向循环主要是因为没有足够的人记住这是您可以做的,并且比正向循环更有效=)

(using reverse looping mostly because not enough people remember that's a thing you can do, and is more efficient than a forward loop =)

您会想象会有一个array_copy函数或一些有助于处理数组复制异常的函数,但是似乎没有.这很奇怪,但是其中之一就是"PHP状态".过去曾做出过选择,因此,PHP沿用了这一选择已有相当多年的历史,因此,这只是其中之一".不幸的是!

You'd imagine there'd be an array_copy function or something to help deal with the array copy quirk, but there just doesn't seem to be one. It's odd, but one of those "the state of PHP" things. A choice was made in the past, PHP's lived with that choice for quite a few years as a result, so it's just "one of those things". Unfortunately!

这篇关于通过引用分配错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆