我试图理解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'。感谢
答案 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']);