Перейти к содержимому
Теория · Массивы · урок 6 из 8

Вложенные массивы

На крючке в гардеробе может висеть не только пальто, но и сумка, а в сумке — свои отделения с бирками. Чтобы достать перчатки, сначала находят крючок, а потом нужное отделение.

С массивами так же: значением элемента может быть другой массив. Массив, который лежит внутри другого массива, называют вложенным массивом. Так хранят, например, список пользователей, где у каждого есть имя и возраст:

PHP
<?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

Давайте разберём по строкам:

  1. $users — список, а каждый его элемент — карточка одного пользователя: ассоциативный массив с ключами 'name' и 'age'.
  2. $users[1]['name'] читается по шагам: $users[1] — карточка Бориса, а ['name'] берёт из неё имя. Печатается Boris.
  3. $users[0]['age'] = 32; проходит тот же путь и меняет возраст прямо внутри карточки Анны.
  4. $users[] = ['name' => 'Vera', 'age' => 19]; добавляет в конец списка целую новую карточку.
  5. count($users) считает карточки, их 3, а возраст Анны теперь 32.

Длинный массив удобно записывать в несколько строк, по элементу на строку. Запятая после последнего элемента разрешена: так новый элемент можно дописать отдельной строкой, не трогая предыдущую.

Два вида вложенности

Список карточек

В $users первый индекс — номер карточки, второй — поле внутри неё: $users[0]['name']. Такую форму берут, когда однотипных данных много и у всех одинаковые поля: пользователи, товары, заказы.

Карточка со списком внутри

Бывает и наоборот: в ассоциативном массиве одно из полей — список. Заглянуть внутрь такого массива помогает print_r: вложенный массив она печатает с дополнительным отступом.

PHP
$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: внешний перебирает карточки, внутренний — пары внутри карточки. Как и в таблице умножения из темы о циклах, строку собирают через .=:

PHP
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

Разберём по шагам:

  1. Внешний цикл кладёт в $user копию очередной карточки.
  2. $line = '' начинает новую строку для каждой карточки.
  3. Внутренний цикл проходит по парам карточки и дописывает в $line ключ, знак = и значение.
  4. После внутреннего цикла echo печатает готовую строку, и внешний цикл берёт следующую карточку.

Здесь картинка с сумкой неточна: в настоящем гардеробе сумку в сумку вкладывают редко. Массивы же вкладывают друг в друга на сколько угодно уровней — например, у каждого пользователя может быть список заказов, а у каждого заказа — список товаров.

Частая ошибка

Поле читают прямо из списка, забыв выбрать карточку:

PHP
echo $users['name'], "\n"; // ✗
TEXT
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.