Позавчера работая над статистикой для 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’.

Удачи!

    Trackback

    only 1 comment untill now

    1. Pashugan @ 2009-02-12 16:04

      test1.php:

      function getmicrotime(){
      list($usec, $sec) = explode(” “,microtime());
      return ((float)$usec + (float)$sec);
      }

      $ar = array(
      ‘asdf’ => ‘asdf’,
      ‘jkl’ => array(
      ‘jfjf’ => 1e25,
      234 => ‘dfksfdsj’,
      ‘xoxoxo’ => array(1,2,3,4,5,6,7,8,9,10),
      ),
      ‘fjfjfjdsfdfsfdsk’ => str_repeat(‘v’, 500),
      );

      for ($i = 0; $i < 100000; $i++) $r[] = $ar;

      $t1 = getmicrotime();
      foreach ($r as &$v);
      $t2 = getmicrotime();

      echo $t2 – $t1.”\n”;
      echo memory_get_peak_usage(true).”\n”;

      Второй файл test2.php точно такой же, но без амперсанда.
      $ php test1.php
      0.143193006516
      32243712
      $ php test2.php
      0.0240671634674
      5505024
      $ php -v
      PHP 5.2.8-pl2-gentoo (cli) (built: Jan 26 2009 12:35:28)

      Вопрос — зачем оно нужно?

    Add your comment now