Поведение PHP и указатели массивов

Я читал руководство по PHP (в частности, each() функция) и наткнулся на следующее предупреждение:

предосторожность
Поскольку присвоение массива другой переменной сбрасывает указатель исходного массива, наш приведенный выше пример вызовет бесконечный цикл, если бы мы присвоили $ fruit другой переменной внутри цикла.

И пример:

<?php
$fruit = array('a' => 'apple', 'b' => 'banana', 'c' => 'cranberry');

reset($fruit);
while (list($key, $val) = each($fruit)) {
echo "$key => $val\n";
}
?>

Хорошо. Это имеет смысл. Но я решил сделать простой тест:

<?php
$fruit = array('a' => 'apple', 'b' => 'banana', 'c' => 'cranberry');

foreach ($fruit as $key => $name) {
printf("[%s] => [%s]\n", $key, $name);
}

$fruit2 = $fruit;
echo current($fruit);
?>

Результат ожидаемый: указатель сброшен. У меня вопрос, если указатель сбрасывается только после конца массива?

Например:

<?php
$fruit = array('a' => 'apple', 'b' => 'banana', 'c' => 'cranberry');

foreach ($fruit as $key => $name) {
printf("[%s] => [%s]\n", $key, $name);
}

reset($fruit);
next($fruit)."\n";
$fruit2 = $fruit;
echo current($fruit);
?>

Указатель остается во втором элементе массива ('b' => 'banana'),
Такое поведение характерно для языка?

Спасибо и извините за плохой английский.

4

Решение

Такое поведение характерно для языка?

Значение «указатель» в массивах PHP не совпадает с общим значением «указатель» (в C / C ++ или других языках, которые дают программисту прямой доступ к памяти).

В PHP нет указателей. массив Тип данных внутренне удерживает курсор внутри списка значений, которые он содержит. Он называется внутренним указателем массива и изменяется функциями reset(), next(), prev(), end(), each() и, возможно, другие. Его можно использовать для перебора массива следующим образом:

$array = array(1, 2, 3);
while (list($key, $val) = each($array)) {
echo($key.' => '.$val."\n");
}

Не существует надежного способа перебора массива с использованием next() или же prev() потому что они возвращаются FALSE когда больше нет элементов для итерации, но они также возвращают FALSE когда значение FALSE хранится как элемент в массиве.

Они могут быть полезны, если вам нужно проанализировать только несколько элементов в начале (или конце) массива. F.E. допустим, у нас есть массив целых чисел, возвращаемых функцией, и нам нужно получить первое значение, которое не равно нулю.

Но эта цель может быть достигнута еще проще, используя foreach():

$array = array(0, 0, 0, 2, 0, 1, 0, 3);
foreach ($array as $val) {
if ($val != 0) {
break;
}
}
echo($val);           // prints "2"

или же array_shift():

$array = array(0, 0, 0, 2, 0, 1, 0, 3);
do {
$val = array_shift($array);
if ($val != 0) {
break;
}
} while(count($array));
echo($val);           // prints "2"

Результат ожидаемый: указатель сброшен. У меня вопрос, если указатель сбрасывается только после конца массива?

Документация foreach() неправильно. Может быть, это было правильно на PHP 3 и PHP 4, но я думаю, что с момента введения итераторы в PHP 5 поведение foreach() изменилось (к лучшему).

Это говорит:

Когда foreach впервые начинает выполняться, внутренний указатель массива автоматически сбрасывается на первый элемент массива. Это означает, что вам не нужно вызывать reset () перед циклом foreach.

Поскольку foreach полагается на внутренний указатель массива, его изменение в цикле может привести к неожиданному поведению.

Простой тест противоречит этому утверждению:

$array = array(1, 3, 5, 7, 9);

foreach ($array as $val1) {
foreach ($array as $val2) {
echo('$val1='.$val1.'; $val2='.$val2.'; ');
}
echo("\n");
}

Работает без проблем. Это не должно работать, если foreach() использует внутренний указатель массива. Вероятно, он создает копию указателя.

Вы также можете попробовать использовать current(), next(), prev() или же reset() внутри foreach() и вы получите удивительные, а иногда и противоречивые результаты.

Вы лучше использовать foreach() перебирать массивы и ни в коем случае не полагаться на внутренний указатель.

Функции reset() а также end() Однако они очень удобны, когда вам нужно получить первый и последний элемент массива, не беспокоясь о ключах.

5

Другие решения

Да, указатель будет сброшен только после окончания массива. Поскольку foreach получает указатель на конец массива, он автоматически сбрасывается после $ fruit2 = $ fruit; а также он будет сброшен, если вы перейдете вручную в конце массива, используя next () как код ниже

<?php
$fruit = array('a' => 'apple', 'b' => 'banana', 'c' => 'cranberry');

foreach ($fruit as $key => $name) {
printf("[%s] => [%s]\n", $key, $name);
}

reset($fruit);
next($fruit)."\n";
next($fruit)."\n";
next($fruit)."\n";
$fruit2 = $fruit;
echo current($fruit);
?>
2