FOR и FOREACH: ссылки и указатели

Давайте представим какую-нибудь тривиальную (не очень, но достаточно простую) задачу. Допустим, мы хотим к каждой строке в массиве добавить длину строки.
Напишем простейший цикл:
foreach ($big_arr as $str)
$str .= " ".strlen($str);
Однако, распечатав массив
 print_r($big_arr);
мы увидим, что не достигли результата, элементы массива остались без изменения. В чем же дело? Давайте разберемся.

Давайте попробуем по-старинке:
for ($i=0;$i<count($big_arr);$i++)
$big_arr[$i] .= " ".strlen($big_arr[$i]);

Длинно? Но зато в итоге мы получили то, что хотели. Почему? Дело в том, что во втром случае с циклом for мы работаем с самим исходным массивом, а в первом (foreach) - с копиями элементов массива.
Поясню. При каждом проходе цикла в нашем случае переменной $str присваивается значение очередного элемента исходного массива, и работая дальше с переменной $str, мы используем это значение, но не сам элемент. То есть, воздействуя на копию элемента массива - мы не затрагиваем исходный массив.
Вот тут-то пора вспомнить о ссылках. Ссылка на переменную - это не новая переменная, а адрес, указатель на область памяти, где хранится исходная переменная. Напишем так:
foreach ($big_arr as &$str) $str .= " ".strlen($str);
Что мы здесь делаем? Теперь мы присваиваем переменной $str не значение очередного элемента массива, а адрес в памяти, где этот элемент хранится, и значит при работе с переменной $str мы будем напрямую работать с этим элементом.
Вот теперь, когда мы не создаем новую переменную $str и копируем в неё значение элемента массива, а создаем указатель $str на область памяти, где этот элемент хранится, всё работает правильно!

Комментарии

Популярные сообщения из этого блога

Обратный звонок в CS-Cart 4.3.x

Обновление сервера 1С:Предприятие на UNIX платформе

CS-Cart: Модули. [AVP] Дополнение для Детектора изменений ядра