Эта тема на forum.dklab.ru


Markus: Foreach и next
PHP Version 5.2.4

$array = array('a','b','c','d','e','f');
foreach($array as $a) {
echo "$a = ".next($array)."<br>";
}
В этой версии получаем на выходе:
a = c
b = d
c = e
d = f
e =
f =

В четвертой же версии
a = b
b = c
c = d
d = e
e = f
f =

при чем current тоже глючит.

Это баг версии 5.2.4 ?

Просто перебирая foreach многомерный массив, мне нужно узнать есть сли следующий элемент массива и если есть получить для сравнения значение элемента.
Здесь упрощенная версия перебора и массив не многомерный, но даже здесь видно, что next работает не коректно. А в скрипте так вообще непонятно как работает.
пришлось пока воспользоваться array_keys
dimagolov:
это полный код? или что-то еще было, но сократили для форума?
в 5.1.4 получился 2-й вариант
Markus:
Это полный код, который для 5.2.4 выводит первый вариант, а для 4.4.4 второй.
ИМХО глюк именно в версии 5.2.4
Юрий Насретдинов:
Markus
Ваш код не должен работать в принципе, поэтому PHP5 тоже прав :). Во время foreach не Вы определяете, какой будет следующий элемент.
Maus:
Markus
в четвёрке foreach() работал с копией массива.
В пятерке сразу должны были использоваться ссылки, а не копии, но была допущена ошибка - кажется, в 5.1.6 её фиксили
dimagolov:
Maus,
пример конечно у автора некорректный, не стоит одновремено использовать 2 ф-ии, которые манипулируют с указателем массива. но тем не менне какая-то ерунда все равно выходит...
Замечание: Unless the array is referenced, foreach operates on a copy of the specified array and not the array itself. Therefore, the array pointer is not modified as with the each() construct, and changes to the array element returned are not reflected in the original array. However, the internal pointer of the original array is advanced with the processing of the array. Assuming the foreach loop runs to completion, the array's internal pointer will be at the end of the array.

As of PHP 5, you can easily modify array's elements by preceding $value with &. This will assign reference instead of copying the value.

как я понял, то есть вопрос о ссылках относится к выдаваемым элементам, чтобы можно было в foreach изменять оригинальный массив.
но вопрос ведь не этом, а в указателе основного массива. видимо он после выдачи каждого значения синхронизируется с копией, иначе такое поведение не объяснить. выходит так:
1. зашли в foreach, $a = 'a', указатель копии и основного на 'b'
2. next передвинул указатель на 'c' и вернул 'c'
3. новая итерация. $a = 'b' - взяли из копии по указателю копии, переместили указатель копии на 'c', скопировали в основной указатель
4. next передвинул указатель на 'd' и вернул 'd'
...
если бы foreach ограничивался просто перемещение указателя а не копированием его позиции из копии, то тогда бы next выдавал значения через одно - один раз его перемещает foreach, второй next
если бы не было копии, по крайней мере указателя, то и $a перескакивало бы через одно значение
Maus:
В мане так и написано:
Therefore, the array pointer is not modified as with the each() construct...However, the internal pointer of the original array is advanced with the processing of the array
Я это понимаю так:
1) Вы не можете повлять на количество итераций в foreach c помощью each(), next() и тому подобного;
2) указатель исходного массива смещается в процессе обработки
Есть другие варианты?
dimagolov:
Maus судя по всему, Ваше понимание соответствует реализации PHP Version 5.2.4. Хотя Ваш п.1 для меня не очевидно следует из цитаты, но так или иначе он соответствует действительности.
Markus:
Все понятно. Собственно я так и думал.
В цикле foreach я не изменяю массив, просто мне в текущей итерации необходимо заглянуть в следующий элемент массива.
Думается неплохо было бы, если бы были функции позволяющие заглянуть в следующий, предыдущий, первый и последний без смещения указателя массива.
Сейчас я выбираю все ключи массива и перебираю массив ключей. Может есть какой другой способ заглянуть вперед в массиве?
Maus:
Markus
можно перестроить цикл: переписать foreach() на reset(...);
while(list(..)=each(...))
Rumata:
Markus
неужели нельзя сделать просто

maxL = array.last;
for (var i = 0; i < array.length - 1; i++) {
if ( array[i] > maxL ) {
maxL = array[i];
}
}

maxF = array.first;
for (var i = 1; i < array.length; i++) {
if ( array[i] > maxF ) {
maxF = array[i];
}
}


если у вас ассоц.массив - можно и советом Maus воспользоваться
Юрий Насретдинов:
Rumata
Эээ, это же PHP...
Rumata:
Юpий Насрeтдинов, а это псевдокод
самый универсальный язык описаний
Viktor_Rez:
Все понятно. Собственно я так и думал.
В цикле foreach я не изменяю массив, просто мне в текущей итерации необходимо заглянуть в следующий элемент массива.
Думается неплохо было бы, если бы были функции позволяющие заглянуть в следующий, предыдущий, первый и последний без смещения указателя массива.
Сейчас я выбираю все ключи массива и перебираю массив ключей. Может есть какой другой способ заглянуть вперед в массиве?


$a = array("a" => "123", "b" => "333", "c" => "fff", "d" => "444");
$b = &$a;

foreach($a as $value)
{

prev($b);
$value2 = next($b);
$str_end = ($value2) ? " следующее значение ".$value2 : " - последний элемент ".$value2;

echo $value.$str_end."<br />";
}


У меня PHP 5.0.1
dimagolov:
Viktor_Rez, о чем это все говорит? какой вывод в итоге дает этот код?
Anonymous:
dimagolov, вывод один - нет ничего невозможного.
dimagolov:
Гость, вывод это то, что выводит скрипт. тема была про то, что поведение foreach поменялось в районе версии 5.1.6. тему надо читать от начала и до конца и внимательно, прежде чем что-то писать.

Эта тема на forum.dklab.ru