Вложенные массивы
На крючке в гардеробе может висеть не только пальто, но и сумка, а в сумке — свои отделения с бирками. Чтобы достать перчатки, сначала находят крючок, а потом нужное отделение.
С массивами так же: значением элемента может быть другой массив. Массив, который лежит внутри другого массива, называют вложенным массивом. Так хранят, например, список пользователей, где у каждого есть имя и возраст:
<?php
$users = [
['name' => 'Anna', 'age' => 31],
['name' => 'Boris', 'age' => 25],
];
echo $users[1]['name'], "\n"; // Boris
$users[0]['age'] = 32;
$users[] = ['name' => 'Vera', 'age' => 19];
echo count($users), ' ', $users[0]['age'], "\n"; // 3 32Давайте разберём по строкам:
$users— список, а каждый его элемент — карточка одного пользователя: ассоциативный массив с ключами'name'и'age'.$users[1]['name']читается по шагам:$users[1]— карточка Бориса, а['name']берёт из неё имя. ПечатаетсяBoris.$users[0]['age'] = 32;проходит тот же путь и меняет возраст прямо внутри карточки Анны.$users[] = ['name' => 'Vera', 'age' => 19];добавляет в конец списка целую новую карточку.count($users)считает карточки, их3, а возраст Анны теперь32.
Длинный массив удобно записывать в несколько строк, по элементу на строку. Запятая после последнего элемента разрешена: так новый элемент можно дописать отдельной строкой, не трогая предыдущую.
Два вида вложенности
Список карточек
В $users первый индекс — номер карточки, второй — поле внутри неё: $users[0]['name']. Такую форму берут, когда однотипных данных много и у всех одинаковые поля: пользователи, товары, заказы.
Карточка со списком внутри
Бывает и наоборот: в ассоциативном массиве одно из полей — список. Заглянуть внутрь такого массива помогает print_r: вложенный массив она печатает с дополнительным отступом.
$order = ['id' => 7, 'items' => ['tea', 'cake']];
$order['items'][] = 'juice';
print_r($order);
// Array
// (
// [id] => 7
// [items] => Array
// (
// [0] => tea
// [1] => cake
// [2] => juice
// )
//
// )Здесь первый ключ — поле заказа, второй — номер в списке: $order['items'][2] даёт 'juice'. Запись $order['items'][] = 'juice' добавляет элемент во вложенный список, как $a[] = … в обычный.
Обход двумя циклами
Чтобы пройти по всем полям всех карточек, нужны два цикла foreach: внешний перебирает карточки, внутренний — пары внутри карточки. Как и в таблице умножения из темы о циклах, строку собирают через .=:
foreach ($users as $user) {
$line = '';
foreach ($user as $field => $value) {
$line .= $field . '=' . $value . ' ';
}
echo $line, "\n";
}
// name=Anna age=32
// name=Boris age=25
// name=Vera age=19Разберём по шагам:
- Внешний цикл кладёт в
$userкопию очередной карточки. $line = ''начинает новую строку для каждой карточки.- Внутренний цикл проходит по парам карточки и дописывает в
$lineключ, знак=и значение. - После внутреннего цикла
echoпечатает готовую строку, и внешний цикл берёт следующую карточку.
Здесь картинка с сумкой неточна: в настоящем гардеробе сумку в сумку вкладывают редко. Массивы же вкладывают друг в друга на сколько угодно уровней — например, у каждого пользователя может быть список заказов, а у каждого заказа — список товаров.
Частая ошибка
Поле читают прямо из списка, забыв выбрать карточку:
echo $users['name'], "\n"; // ✗Warning: Undefined array key "name"В $users ключи — номера карточек 0, 1 и 2, а ключ 'name' есть только внутри каждой карточки. PHP выдаёт предупреждение и печатает пустую строку. Сначала выберите карточку, потом поле: $users[0]['name'].
Главное
- Значением элемента может быть другой массив;
$users[1]['name']читается по шагам: сначала карточка, потом поле. - Запись по такому пути,
$users[0]['age'] = 32, меняет значение внутри вложенного массива. - Вложенный массив обходят двумя циклами
foreach: внешний по карточкам, внутренний по их полям. print_rпоказывает вложенный массив с отступами, а чтение поля без выбора карточки даётWarning: Undefined array key.