按引用传递如何或为什么用 PHP 覆盖其他引用?

How or why does passing by reference overwrite other references with PHP?

有人可以向我解释为什么引用变量传递的行为与我所看到的一样吗?

这是我正在处理的控制器中的一个方法:

public function view($view,$context=array()){
    // <snip>
    foreach($context as $a=>$b){
        $$a = $b;
    }
    // <snip>
}

它将数据 $context 数组复制到本地范围,以便在调用(包含)视图时它可以访问元素。

$foo->method(); // first thing
$bar->method(); // second thing

有点大惊小怪,我想使用实际对象而不是副本(这看起来很浪费)所以我将其更改为:

public function view($view,$context=array()){
    // <snip>
    foreach($context as $a=>$b){
        $$a =& $b;
    }
    // <snip>
}

那是我目睹了一些我没有预料到的事情。

$foo->method(); // second thing!!
$bar->method(); // second thing

在测试用例中,将两个对象传递给视图,然后视图输出相关数据。当通过引用而不是通过值传递时,两个变量都以对第二个对象的引用结束。

我没想到会发生这种情况。我非常希望有人向我解释为什么会这样。我可能错过了一些明显的东西,所以请教育我。

万一它是相关的(我怀疑它可能是但我不确定)。

方法是这样调用的:

$data = array();
$data['foo'] =& $this->module()->get_foo();
$data['bar'] =& $this->module()->get_bar();
$this->view('nameOfView',$data);

在此实例中通过引用获取 return,因此此处的 & 可能有点矫枉过正。再一次,我不像我想的那样确定。出于这个问题的目的,我只是 真的 想了解视图方法中的引用覆盖是怎么回事,但请随时教我其他我应该知道但显然不知道的事情t.

因为变量 $b 正在被 foreach 循环重用。
随着 $b 被重新分配,所有对它的引用也被重新分配。

简单示例:

$a = [1, 2, 3];
$c = [];
foreach($a as $b)
{
    $c[] = &$b;
}
print_r($c);

产生:

Array
(
    [0] => 3
    [1] => 3
    [2] => 3
)

您甚至可以更进一步,在 foreach 循环之后进行赋值:

$b = 'derp';

这会将你的数组变成这样:

Array
(
    [0] => derp
    [1] => derp
    [2] => derp
)

现在,正如到目前为止在评论中提到的两次,有一个名为 extract() 的函数,它似乎是为您正在尝试做的事情而设计的,这就是我建议的方式一起去。

但是为了完整起见,"fix" 您的代码相当简单。
有两种方法可以做到这一点:

  • $b 设为参考而非副本。
    您可以通过使用 $a as &$b 作为 foreach:

    的参数来做到这一点
    $a = [1, 2, 3];
    $c = [];
    foreach($a as &$b)
    {
        $c[] = &$b;
    }
    print_r($c);
    
  • 在重新分配之前断开对 $b 的引用。
    您可以通过在循环结束时调用 unset($b); 来做到这一点:

    $a = [1, 2, 3];
    $c = [];
    foreach($a as $b)
    {
        $c[] = &$b;
        unset($b);
    }
    print_r($c);
    

以上两个都会给你最初预期的结果:

Array
(
    [0] => 1
    [1] => 2
    [2] => 3
)

请注意,当您使用第一种方式并在此之后修改 $a 时,$c 也可能会发生变化,但并非总是如此。
例如,直接赋值 ($a[0] = 5;) 将影响 $c ($c[0] == 5).
$c 不受 $a 上的任何其他操作的影响(据我所知),但在 $a 中的索引混乱之后(与 array_shift()shuffle()), $c[1] 可能是对 $a[0] 等的引用

如果你不想头疼,就选择extract()