for-each循环中的引用如何更改数组的元素?

时间:2014-09-21 14:22:16

标签: php arrays reference

$arr=array('a'=>'first','b'=>'second','c'=>'third');
foreach($arr as &$a);
foreach($arr as $a);
print_r($arr);

上面的代码更改了$arr ['c'=>'second']的最后一个元素。它是如何做到的?

1 个答案:

答案 0 :(得分:3)

您正在第一个循环中创建引用。在循环结束时$a仍然是对数组中最后一个值的引用:

$arr = ['a','b','c'];
foreach($arr as &$a);
debug_zval_dump($arr,$a);

array(3) refcount(2){
  [0]=>
  string(1) "a" refcount(1)
  [1]=>
  string(1) "b" refcount(1)
  [2]=>
  &string(1) "c" refcount(2)
}

因此,为$ a分配内容会改变该值:

//... previous code, and then:
$a = 'I am still a reference';
debug_zval_dump($arr);

array(3) refcount(2){
  [0]=>
  string(1) "a" refcount(1)
  [1]=>
  string(1) "b" refcount(1)
  [2]=>
  &string(22) "I am still a reference" refcount(2)
}

...所以,如果你做第二次foreach,就会发生这种情况:数组中的最后一项将采用第一项的值,因此它的原始值将丢失,并且数组的所有后续项都将丢失。但是,当它设置为自身(最后一个)时,其原始值已经丢失,并且它不会更改任何内容,因此数组的最后一个值将采用最后一个项目的值:

foreach($arr as $a){
    debug_zval_dump($arr);
}

array(3) refcount(3){
  [0]=>
  string(1) "a" refcount(1)
  [1]=>
  string(1) "b" refcount(1)
  [2]=>
  &string(1) "a" refcount(2)
}
array(3) refcount(3){
  [0]=>
  string(1) "a" refcount(1)
  [1]=>
  string(1) "b" refcount(1)
  [2]=>
  &string(1) "b" refcount(2)
}
array(3) refcount(3){
  [0]=>
  string(1) "a" refcount(1)
  [1]=>
  string(1) "b" refcount(1)
  [2]=>
  &string(1) "b" refcount(2)
}

简而言之:在循环中使用引用时总是这样做,除非你有非常的理由不:

foreach($array as &$a){
    // some logic
}
unset($a); // removes the reference, so you can't accidentally assign something to it and thereby mutate $array itself.