Позавчера работая над статистикой для UMapper‘a наткнулся на странный баг, который (как выяснилось сегодня) я совсем не понял. Совпадения случаются, и вот сегодня читая PHP5 Zend Certification Guide, наткнулся на объяснение. Сначала код:

1
2
3
4
5
6
$vars = array('a', 'b', 'c');
 
foreach ($vars as &$v);
foreach ($vars as $v);
 
print_r($vars);

Как вы думаете, каков будет результат выполнения приведенного кода? А вот такой:

1
2
3
4
5
Array(
  [0] => a
  [1] => b
  [2] => b
)

Если ответили правильно – зачет, если же нет – читайте объяснение, так как это не баг.
На самом деле все довольно просто: внутри первого цикла, только на первый взгляд ничего не происходит, на самом деле создается ссылка $v, и далее при каждой итерации ссылка указывает на текущий элемент массива. Таким образом после окончания цикла $v = &$vars[2], т.е. переменная $v является ссылкой на последний элемент массива. Во втором цикле, переменная $v при каждой итерации получает значение текущего элемента, а так как переменная является ссылкой обновляется и $vars[2]:
1-я итерация: $v = $vars[0]; => $vars[2] = $vars[0]; // $vars[2] = ‘a’
2-я итерация: $v = $vars[1]; => $vars[2] = $vars[1]; // $vars[2] = ‘b’
3-я итерация: $v = $vars[2]; => $vars[2] = $vars[2]; // $vars[2] = ‘b’ – так как на момент присваивания значение $vars[2] было измененно предыдущей итерацией на ‘b’.

Удачи!