Долгое время я предполагал, что foreach работает с самим массивом. Затем я нашел много упоминаний о том, что он работает с копией массива, и с тех пор предположил, что на этом история закончилась. Но недавно я вступил в дискуссию по этому поводу и после небольшого экспериментирования обнаружил, что на самом деле это не на 100% правда.
Позвольте мне показать, что я имею в виду. В следующих тестовых случаях мы будем работать со следующим массивом:
Код: Выделить всё
$array = array(1, 2, 3, 4, 5);
Код: Выделить всё
foreach ($array as $item) {
echo "$item\n";
$array[] = $item;
}
print_r($array);
/* Output in loop: 1 2 3 4 5
$array after loop: 1 2 3 4 5 1 2 3 4 5 */
Тестовый пример 2:
Код: Выделить всё
foreach ($array as $key => $item) {
$array[$key + 1] = $item + 2;
echo "$item\n";
}
print_r($array);
/* Output in loop: 1 2 3 4 5
$array after loop: 1 3 4 5 6 7 */
Если мы посмотрим в руководство, то обнаружим следующее утверждение:
Когда foreach впервые начинает выполнение, указатель внутреннего массива автоматически сбрасывается на первый элемент массива.
Верно... похоже, это предполагает, что foreach полагается на указатель массива исходный массив. Но мы только что доказали, что не работаем с исходным массивом, верно? Ну, не совсем.
Тестовый пример 3:
Код: Выделить всё
// Move the array pointer on one to make sure it doesn't affect the loop
var_dump(each($array));
foreach ($array as $item) {
echo "$item\n";
}
var_dump(each($array));
/* Output
array(4) {
[1]=>
int(1)
["value"]=>
int(1)
[0]=>
int(0)
["key"]=>
int(0)
}
1
2
3
4
5
bool(false)
*/
В руководстве PHP также говорится:
Поскольку foreach полагается на указатель внутреннего массива, его изменение в цикле может привести к неожиданному поведению.
Что ж, давайте выясним, что это за «неожиданное поведение» (технически любое поведение является неожиданным, поскольку я больше не знаю, чего ожидать).
Тестовый пример 4:
Код: Выделить всё
foreach ($array as $key => $item) {
echo "$item\n";
each($array);
}
/* Output: 1 2 3 4 5 */
Код: Выделить всё
foreach ($array as $key => $item) {
echo "$item\n";
reset($array);
}
/* Output: 1 2 3 4 5 */
Вопрос
Что здесь происходит? Мой C-fu недостаточно хорош, чтобы я мог сделать правильный вывод, просто взглянув на исходный код PHP. Я был бы признателен, если бы кто-нибудь мог перевести его на английский для меня.
Мне кажется, что foreach работает с копией массива, но после цикла устанавливает указатель исходного массива в конец массива.
- Правильно ли это и вся история?
- Если нет, то что он на самом деле делает?
- Есть ли ситуация, когда используются функции, корректирующие указатель массива (, reset() и др.) во время foreach могут повлиять на результат цикла?
Код: Выделить всё
each()
Подробнее здесь: https://stackoverflow.com/questions/100 ... ually-work
Мобильная версия