PHP中的链接引用

时间:2013-09-28 13:25:20

标签: php reference

我试图理解PHP引用,但在使用链接引用时我发现了一个问题。

class A
{
    public $val;

    public function __construct($val)
    {
        $this->val = $val;
    }
}

$values = array(
    'a' => new A('a'),
    'b' => new A('b'),
    'c' => new A('c')
);

$values['a'] = &$values['b'];
$values['b'] = &$values['c'];

返回:

array(
'a' => new A('b'),
'b' => new A('c'),
'c' => new A('c')
)

对象A中为什么'val'表示键'a'是'b'?我预计价值将是'c'。感谢

3 个答案:

答案 0 :(得分:1)

$values['b']分配给$values['a']时,

~$ php -a php > $values = array(); php > $values['c'] = 1; php > $values['b'] = &$values['c']; php > $values['a'] = &$values['b']; php > print_r($values); Array ( [c] => 1 [b] => 1 [a] => 1 ) 不存在。如果您更改了订单,则按照您的描述进行操作:

{{1}}

答案 1 :(得分:1)

尽量避免引用,它们可能会让您遇到难以调试的麻烦。此外,在幕后引用对象;这意味着:

$a1 = new A('a');
$a2 = $a1;

类似

$b1 = new A('a');
$b2 = &$b1;

顺便说一下:

$a2->val = 1; // $a1->val is now equal to 1, because $a1 and $a2 are pointing 
              // to the same instance
$b2->val = 1; // $b1->val is now equal to 1, because $b2 points to $b1

但是有一个微妙的区别:

$a1 = 1; // $a2 still points to A object
$b1 = 1; // $b2 still points to $a1 which points to number 1,
         // therefore $b2 == 1

它与数组的工作方式略有不同,因为数组赋值总是涉及值复制。

如果你想了解你的例子中发生了什么,让我们来看看:

所以你原来的数组是这样的:

$values = array(
    'a' => new A('a'),
    'b' => new A('b'),
    'c' => new A('c')
);

让我们一步一步看看会发生什么:

$values['a'] = &$values['b']; // $values['a'] is now reference to new A('b')
                              // that means your original new A('a') is now
                              // lost

$values['b'] = &$values['c']; // $values['b'] is now reference to new A('c')
                              // stored under 'c' key, that means $values['b']
                              // is now equal to $values['c'] ; note that this is 
                              // different than $b2 = &$b1; from the above example
                              // since we use an array and not bare variables
                              // the $values['a'] points to value stored under 
                              // the 'b' key, but we replace the 'b' key value 
                              // as opposed to giving it a new value; 
                              // "Array assignment always involves value copying."

// So you ended up with this result:
array(
  'a' => new A('b'),
  'b' => new A('c'), // this is actually reference to 'c', just wrote new A() 
                     // to keep this part consistent with your question's
                     // formatting
  'c' => new A('c') 
)

答案 2 :(得分:0)

注意:这个答案是the question as originally asked。新问题有些不同,尽管在这种情况下对象的使用不会改变基本行为。

PHP引用不能被“链接” - =&运算符不像指针引用/去引用机制,它将两个(或更多)变量绑定在一起。但重要的是,变量名称都不比另一个更“真实” - 它们是 (或所有)对无名值的引用。

例如,$foo =& $bar获取$bar指向的值和 $foo的值。如果您随后分配给任一变量(例如$foo = 42;$bar = 42;),则会更新该值。某些操作(例如unset($bar))作用于变量,而不是,因此它们仅影响该特定变量,而不影响参考值。

您可以通过运行此操作来查看此操作:$foo = 42; $bar =& $foo; unset($foo); echo $bar;请注意$foo是该值的“原始”名称,但即使在取消设置后,该值仍然存在。然后,您可以将变量$foo重用为完全不同的值,而不会以任何方式影响$bar

如果你接受一个已经是引用的变量,并使其成为对其他内容的引用,那就像取消设置引用并重用变量名来设置一个新引用。因此不受影响,以前引用的变量名称变得独立。

在您的代码中,您执行此操作:

// 1: Make $values['a'] point to the value currently pointed at by $values['b']
$values['a'] =& $values['b']; 
// 2: Make $values['b'] point to the value currently pointed at by $values['c']
//    the previous value is now only pointed to by $values['a']
$values['b'] =& $values['c']; 
// 3: Set the value shared by $values['b'] and $values['c'] to 1
$values['c'] = 1; 

(作为一个技术细节,我在这里所称的“值”是PHP内部的一个结构,称为zval。)

修改已更新的问题:

对象似乎会使这更加复杂,因为它们具有额外级别的间接,它的工作方式几乎相同:$foo = new A('a'); $bar = $foo;仍会创建两个zval s)但这些值都是指向同一对象的指针。

在你的情况下,这没有区别,因为你仍在使用引用分配(=&) - 如果你没有,你会得到相同的结果:

// 1: Make the value of $values['a'] point to the object currently pointed at by the value of $values['b']
$values['a'] = $values['b']; 
// 2: Make the value of $values['b'] point to the object currently pointed at by the value of $values['c']
//    the previous object is now only pointed to by the value of $values['a']
$values['b'] = $values['c']; 

我们现在有三件事情可以改变:变量,它指向的,以及指向的对象

// Change the object: updates the object shared by $values['b'] and $values['c']
$values['c']->value = 42;
// Change the value: will only update $values['b'] if =& was used to tie them together
$values['c'] = 42; 
// Change the variable: will never affect $values['b']
unset($values['c']);