PHP проходит по ссылке в foreach [дубликат]
этот вопрос уже есть ответ здесь:
Странное поведение foreach
2 ответы
У меня есть этот код:
$a = array ('zero','one','two', 'three');
foreach ($a as &$v) {
}
foreach ($a as $v) {
echo $v.PHP_EOL;
}
может кто-нибудь объяснить, почему вывод:
ноль один два два .
из учебного пособия по сертификации zend.
9 ответов:
потому что на второй цикл,
$vпо-прежнему является ссылкой на последний элемент массива, поэтому он перезаписывается каждый раз.вы можете видеть это так:
$a = array ('zero','one','two', 'three'); foreach ($a as &$v) { } foreach ($a as $v) { echo $v.'-'.$a[3].PHP_EOL; }Как вы можете видеть, последний элемент массива принимает текущее значение цикла: "ноль", "один", "два", а затем это просто "два"... :)
мне пришлось потратить несколько часов, чтобы выяснить, почему[3] меняется на каждой итерации. Вот объяснение, к которому я пришел.
в PHP есть два типа переменных: обычные переменные и ссылочные переменные. Если мы назначаем ссылку на переменную другой переменной, переменная становится ссылочной переменной.
например
$a = array('zero', 'one', 'two', 'three');если мы делаем
$v = &$a[0]элемент 0-й (
$a[0]) становится ссылкой переменная.$vуказывает на эту переменную; поэтому, если мы внесем какие-либо изменения в$v, это будет отражено в$a[0]и наоборот.теперь, если мы делаем
$v = &$a[1]
$a[1]станет ссылочной переменной и$a[0]станет нормальной переменной (так как никто не указывает на$a[0]он преобразуется в нормальную переменную. PHP достаточно умен, чтобы сделать его нормальной переменной, когда никто другой не указывает на нее)вот что происходит в первом цикле
foreach ($a as &$v) { }после последней итерации
$a[3]является ссылочной переменной.С
$vуказывает$a[3]изменения$vприводит к изменению в$a[3]во втором контуре,
foreach ($a as $v) { echo $v.'-'.$a[3].PHP_EOL; }на каждой итерации как
$vизменения$a[3]изменения. (потому что$vуказан$a[3]). Вот почему$a[3]изменения на каждой итерации.в итерация перед последней итерацией,
$vприсваивается значение 'два'. Так как$vуказывает на$a[3],$a[3]теперь получает значение 'два'. Имейте это в виду.в последней итерации,
$v(который указывает на$a[3]) теперь имеет значение 'два', потому что$a[3]было установлено значение два в предыдущей итерации.twoпечати. Это объясняет, почему " два " повторяется, когда $v печатается в последней итерации.
Я думаю, что этот код показывает процедуру более ясно.
<?php $a = array ('zero','one','two', 'three'); foreach ($a as &$v) { } var_dump($a); foreach ($a as $v) { var_dump($a); }результат: (Обратите внимание на два последних массива)
array(4) { [0]=> string(4) "zero" [1]=> string(3) "one" [2]=> string(3) "two" [3]=> &string(5) "three" } array(4) { [0]=> string(4) "zero" [1]=> string(3) "one" [2]=> string(3) "two" [3]=> &string(4) "zero" } array(4) { [0]=> string(4) "zero" [1]=> string(3) "one" [2]=> string(3) "two" [3]=> &string(3) "one" } array(4) { [0]=> string(4) "zero" [1]=> string(3) "one" [2]=> string(3) "two" [3]=> &string(3) "two" } array(4) { [0]=> string(4) "zero" [1]=> string(3) "one" [2]=> string(3) "two" [3]=> &string(3) "two" }
Я попал сюда случайно, и вопрос ОП привлек мое внимание. К сожалению, я не понимаю ни одного объяснения сверху. Мне кажется, что все это знают, понимают, принимают, просто не могут объяснить.
к счастью, чистое предложение из документации PHP на foreach делает это совершенно ясным:
предупреждение: ссылка
$valueи последний элемент массива остается даже после того, как цикл foreach. Рекомендуется уничтожить его с помощью unset ().
этот вопрос имеет много объяснений, но нет четких примеров того, как решить проблему, вызванную этим поведением. В большинстве случаев вам, вероятно, понадобится следующий код в вашем проходе по ссылке
foreach.foreach ($array as &$row) { // Do stuff // Unset unset($row); }
это :
$a = array ('zero','one','two', 'three'); foreach ($a as &$v) { } foreach ($a as $v) { echo $v.PHP_EOL; }это то же самое, что
$a = array ('zero','one','two', 'three'); $v = &$a[3]; for ($i = 0; $i < 4; $i++) { $v = $a[$i]; echo $v.PHP_EOL; }или
$a = array ('zero','one','two', 'three'); for ($i = 0; $i < 4; $i++) { $a[3] = $a[$i]; echo $a[3].PHP_EOL; }или
$a = array ('zero','one','two', 'three'); $a[3] = $a[0]; echo $a[3].PHP_EOL; $a[3] = $a[1]; echo $a[3].PHP_EOL; $a[3] = $a[2]; echo $a[3].PHP_EOL; $a[3] = $a[3]; echo $a[3].PHP_EOL;
Я нашел этот пример также сложнее. Почему во 2-м цикле на последней итерации ничего не происходит ($v остается "два"), заключается в том, что $v указывает на $a[3] (и наоборот), поэтому он не может присвоить себе значение, поэтому он сохраняет предыдущее присвоенное значение:)
потому что если вы создадите ссылку на переменную, все имена для этой переменной (включая оригинал) станут ссылками.
Comments