PHP数组引用混淆

3

使用以下代码:

$a[1]=1;
$a[2]=& $a[1];

$b=$a;
$b[2]=7;

print_r($a);

我原本期望输出结果是1,因为$a并没有被引用赋值给$b$a = & $b),但实际输出结果是7。为什么呢?

3个回答

4
你正在按值复制数组,但源数组的元素是引用。这些引用只是浅复制到目标位置。
php > var_dump($a);
array(2) {
  [1]=>
  &int(1)
  [2]=>
  &int(1)
}
php > $b=$a;
php > var_dump($b);
array(2) {
  [1]=>
  &int(1)
  [2]=>
  &int(1)
}

以下是一个通过引用复制数组的例子:

php > $c[1] = 1;
php > $c[2] =& $c[1];
php > var_dump($c);
array(2) {         
  [1]=>            
  &int(1)
  [2]=>
  &int(1)
}
php > $d =& $c;
php > var_dump($d);
array(2) {
  [1]=>
  &int(1)
  [2]=>
  &int(1)
}
php > $d = array(3,4,5);
php > var_dump($c);
array(3) {
  [0]=>
  int(3)
  [1]=>
  int(4)
  [2]=>
  int(5)
}
php > var_dump($d);
array(3) {
  [0]=>
  int(3)
  [1]=>
  int(4)
  [2]=>
  int(5)
}

正如你所见,数组变量(而不是元素)本身就是一个引用,因此修改 $d 会影响到 $c。重新分配 $b 本身对 $a 没有影响。


3
这就是引用的工作方式。当您执行 $a[2]=& $a[1]; 时,表示 $a 的两个元素现在都持有同一个变量。当您执行 $b = $a 时,$b 和 $a 是不同的变量,但它们内部的所有4个元素指向同一个变量!尝试执行 $b[3] = 7 并查看是否复制到 $a - 因为 $b 和 $a 是不同的,但 $b[2] 和 $a[2] 不是!

引用可能会有些混乱,抱歉。除非必须使用它们,否则请避免使用。


2
虽然解释很好,但避免使用引用的建议并不正确。 - bcosca
谢谢,我觉得你的解释更易懂,但也感谢马修。 - webSol
@stillstanding:如果必须使用它们,那么一定要使用。但在许多情况下并不是必要的——例如,我曾经看到过使用引用与对象或通过引用传递数组“为了提高速度”的php4代码。这是不应该做的。当然,也有合法的引用用法。 - StasM

0

这帮助我理解了什么是引用:

http://www.php.net/manual/en/features.gc.refcounting-basics.php

http://books.google.com/books?id=e7D-mITABmEC&pg=PT171&lpg=PT171&dq=php+object+zval&source=bl&ots=oawmzMtsXt&sig=mMSuVKsk6L3JWuEikJN8j7dQfRs&hl=ru&ei=JmDWTOraI4TNswaDt-jkCA&sa=X&oi=book_result&ct=result&resnum=10&ved=0CEcQ6AEwCQ#v=onepage&q=php%20object%20zval&f=false

而且使用xdebug进行调试有助于解决有趣的案例

例如,您可以"避免"使用私有属性:

class c{
    private $a = 42;
    function &a(){
        return $this->a;
    }
    function print_a(){
        echo $this->a;
    }
}
$c = new c;
$d = &$c->a();
echo $d;
$d = 2;
$c->print_a();

或者在函数中引用传递参数(未声明为引用):

function f1(&$s) {
    $s++;
}
function f2($s) {
    $s--;
}
$s1 = 1;
$s2 = 3;
f1($s1);
f2(&$s2);
echo $s1.$s2;

此外,foreach循环也可以使用引用传递:

$a = array(1,2,3); foreach ( $a as $key => &$value ) { $value = 1; } $value = 2;


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接