PHP中数组引用赋值后再次赋值未复制数组的问题咨询
$b = $a没有创建数组副本,反而修改$b时$a同步变化? 先还原你的代码场景:
$a = [1,2]; $b = &$a; // $b holds reference to $a $b[] = 3; // so this makes $a to {1,2,3} $b = $a; // $b now holds COPY of $a (not reference) - 这是你的预期,但实际不符 $b[] = 4; // so $a must be the same {1,2,3} var_dump($a); // but it isn't - $a is {1,2,3,4}
这是PHP引用机制里非常典型的误区,咱们一步步拆解每一步的变量状态,就能搞清楚问题根源:
初始化数组
$a = [1,2];
此时$a指向一个数组对象,这个数组的**引用计数(refcount)**是1,且没有被标记为引用(is_ref为false)。创建引用关系
$b = &$a;
现在$b成为$a的别名——它们本质上是同一个变量,共享同一个数组对象。此时数组的refcount变为2,is_ref被标记为true(因为存在活跃的引用关系)。通过引用修改数组
$b[] = 3;
因为$b是$a的引用,修改$b就是直接修改共享的数组,所以$a同步变成[1,2,3],这部分符合你的预期。关键误解:赋值操作的实际行为
$b = $a;
你以为这行代码会给$a创建副本并赋值给$b,从而断开引用,但实际不是!
因为$b当前是$a的引用,这行代码等价于把$a的值(也就是那个数组)赋给$a自己。PHP处理这种“给自己赋值”的操作时,不会创建任何副本——它只会把数组的is_ref标记改为false(此时不再需要维持引用标记),但$b和$a仍然指向同一个数组对象,refcount降回1。修改
$b同步影响$a$b[] =4;
现在数组的refcount是1,is_ref是false,属于普通数组变量操作,直接修改数组内容即可,不会触发写时复制(COW)。所以$b修改的还是$a指向的同一个数组,$a自然也会变成[1,2,3,4]。
如何实现你的预期?
如果你想让$b成为$a的独立副本,需要先解除$b和$a的引用关系,再赋值:
$a = [1,2]; $b = &$a; $b[] = 3; unset($b); // 解除$b和$a的引用绑定 $b = $a; // 此时才会创建$a的副本赋值给$b $b[] = 4; var_dump($a); // 输出: array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) }
或者用array_values()强制生成数组副本,跳过解除引用的步骤:
$b = array_values($a); // 直接生成新的数组副本
这样后续修改$b就不会影响$a了。
内容的提问来源于stack exchange,提问作者Agnius Vasiliauskas

