Итерация по массивам через foreach в PHP
Цикл foreach для массивов в PHP
Основная конструкция цикла foreach предназначена для перебора всех элементов массива без необходимости заботиться о счётчиках или условиях выхода. Она работает как с обычными (индексированными), так и с ассоциативными массивами. Базовая запись:
$array = ['яблоко', 'банан', 'вишня'];
foreach ($array as $value) {
echo $value . ' ';
}Foreach php массивы (цикл foreach для массивов в php)
Результат:
яблоко банан вишня
Цикл автоматически проходит по всем элементам, начиная с первого. Переменная $value на каждом шаге содержит текущий элемент. Эта форма подходит, когда ключи не важны.
Как получить и ключ, и значение?
Если требуется не только значение, но и ключ (индекс или имя), используется расширенный синтаксис:
$ages = ['Иван' => 25, 'Мария' => 30, 'Пётр' => 28];
foreach ($ages as $name => $age) {
echo "$name: $age лет\n";
}Результат:
Иван: 25 лет Мария: 30 лет Пётр: 28 лет
Этот способ удобен при работе с ассоциативными массивами, когда нужно использовать ключи в логике.
Типичная ошибка: попытка изменить значение напрямую в $value без ссылки. Переменная $value является копией элемента, поэтому изменение не влияет на исходный массив. Для изменения нужно использовать ссылку (см. следующий раздел).
Как изменить элементы массива внутри цикла?
Для модификации элементов внутри foreach применяется передача по ссылке через амперсанд перед переменной значения:
$numbers = [1, 2, 3, 4];
foreach ($numbers as &$value) {
$value *= 2;
}
unset($value); // обязательно для сброса ссылки
print_r($numbers);Результат:
Array
(
[0] => 2
[1] => 4
[2] => 6
[3] => 8
)После завершения цикла рекомендуется вызывать unset($value), чтобы избежать случайного изменения последнего элемента при дальнейшем использовании переменной.
Проблема: если не выполнить unset, переменная $value останется ссылкой на последний элемент. Любое последующее присваивание этой переменной изменит массив. Это частая причина трудноуловимых багов.
Как обойти многомерный массив?
Для вложенных массивов foreach можно вкладывать друг в друга. Пример с двумерным массивом:
$matrix = [
['a', 'b'],
['c', 'd']
];
foreach ($matrix as $row) {
foreach ($row as $cell) {
echo $cell . ' ';
}
echo '\n';
}Результат:
a b c d
Для ассоциативных вложенных массивов можно использовать конструкцию list() или короткий синтаксис [...] в PHP 7.1+:
$users = [
['name' => 'Alice', 'age' => 30],
['name' => 'Bob', 'age' => 25]
];
foreach ($users as ['name' => $name, 'age' => $age]) {
echo "$name ($age)\n";
}Результат:
Alice (30) Bob (25)
Ошибка: если массив на каком-то уровне окажется не массивом, вложенный цикл вызовет ошибку. Перед вложенным обходом стоит проверять тип is_array() или использовать is_iterable().
Как прервать выполнение цикла или пропустить итерацию?
break досрочно завершает цикл, continue переходит к следующей итерации. Можно указать числовой аргумент для выхода из нескольких уровней вложенности.
$items = [1, 2, 'stop', 4, 5];
foreach ($items as $item) {
if ($item === 'stop') {
break;
}
echo $item . ' ';
}Результат:
1 2
Пример с continue:
foreach ($items as $item) {
if (!is_numeric($item)) {
continue;
}
echo $item * 2 . ' ';
}Результат:
2 4 8 10
Как проверить, что массив не пуст, перед foreach?
Если массив пуст, цикл не выполнит ни одной итерации, что безопасно. Однако иногда нужно выполнить альтернативные действия или избежать предупреждений, если переменная может быть не массивом. Рекомендуется использовать is_array() или !empty():
$data = getSomeData(); // может быть null
if (!empty($data)) {
foreach ($data as $value) {
// обработка
}
} else {
echo 'Данные отсутствуют';
}Распространённая ошибка: передача не массива (например, null) напрямую в foreach приводит к ошибке Invalid argument supplied for foreach. Всегда стоит проверять тип.
Расширенные примеры использования foreach
Ниже приведены более сложные и нестандартные сценарии применения цикла foreach.
Пример 1. Обход и обработка элементов с сохранением ключей и формирование нового массива
$input = ['first' => 10, 'second' => 20, 'third' => 30];
$result = [];
foreach ($input as $key => $value) {
$result[$key] = $value * 2;
}
print_r($result);Array
(
[first] => 20
[second] => 40
[third] => 60
)Пример 2. Использование list() для распаковки вложенных массивов (PHP 5.5+)
$pairs = [[1, 'one'], [2, 'two'], [3, 'three']];
foreach ($pairs as list($num, $word)) {
echo "$num - $word\n";
}1 - one 2 - two 3 - three
Тот же синтаксис с квадратными скобками (PHP 7.1+):
foreach ($pairs as [$num, $word]) {
echo "$num - $word\n";
}Пример 3. Изменение массива во время итерации и его последствия
Изменение ключей или добавление элементов внутри foreach может привести к неожиданному поведению. В примере ниже массив модифицируется, но PHP продолжает итерацию по первоначальному внутреннему указателю:
$arr = [1, 2, 3, 4];
foreach ($arr as $k => &$v) {
if ($v == 2) {
$arr[5] = 100; // добавление нового элемента
}
$v *= 10;
}
unset($v);
print_r($arr);Array
(
[0] => 10
[1] => 20
[2] => 30
[3] => 40
[5] => 100
)Обратите внимание: элемент с индексом 5 не был обработан циклом, так как он появился уже после прохода первых четырёх.
Пример 4. Обход строки как массива символов
В PHP строки можно рассматривать как массивы символов (используя квадратные скобки), но foreach для строк напрямую не применяется. Для итерации по символам нужно преобразовать строку в массив:
$str = 'PHP';
foreach (str_split($str) as $char) {
echo $char . '-';
}P-H-P-
Пример 5. Использование continue 2 для выхода из двух вложенных циклов
$outer = [0, 1, 2];
$inner = [3, 4, 5];
foreach ($outer as $o) {
foreach ($inner as $i) {
if ($o == 1 && $i == 4) {
continue 2; // перейти к следующей итерации внешнего цикла
}
echo "($o,$i) ";
}
echo "\n";
}(0,3) (0,4) (0,5) (1,3) (2,3) (2,4) (2,5)
В строке с o=1 и i=4 был пропущен не только внутренний вывод, но и все последующие итерации внутреннего цикла.
Пример 6. Использование foreach с объектами, реализующими интерфейс Traversable (например, ArrayIterator)
$iterator = new ArrayIterator(['x', 'y', 'z']);
foreach ($iterator as $key => $val) {
echo "$key => $val\n";
}0 => x 1 => y 2 => z
Это позволяет применять foreach к любому итерируемому объекту, не являющемуся массивом.
Пример 7. Безопасное удаление элементов массива во время итерации
Удалять элементы внутри foreach по ссылке на ключ можно через unset, но это может нарушить индексацию. Лучше создавать новый массив или использовать array_filter. Пример с удалением после цикла:
$data = ['a', 'b', 'c', 'd'];
$remove = ['b', 'd'];
foreach ($data as $k => $v) {
if (in_array($v, $remove)) {
unset($data[$k]);
}
}
print_r($data);Array
(
[0] => a
[2] => c
)Ключи сохраняются; для переиндексации можно применить array_values().