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

Ассоциативные массивы

В прошлом уроке вещи висели на крючках с номерами. Но номер ничего не говорит о вещи: под каким номером в меню кафе чай — 0 или 2? Удобнее, когда у каждой вещи есть понятное имя.

Представьте, что в гардеробе вместо номерков выдают бирки с именами. Пальто Анны висит под биркой anna, куртка Бориса — под биркой boris. Чтобы забрать вещь, достаточно назвать имя.

Массив, в котором значения находят не по номеру, а по имени, называют ассоциативным массивом. То, по чему находят значение, называют ключом: в списке это номер, в ассоциативном массиве — имя. Вот меню кафе, где ключом служит название напитка, а значением — цена:

PHP
<?php

$prices = ['tea' => 120, 'coffee' => 180];
$prices['juice'] = 150;
$prices['tea'] = 100;
echo $prices['coffee'], ' ', count($prices), "\n"; // 180 3
foreach ($prices as $drink => $price) {
    echo $drink, ': ', $price, "\n";
}
// tea: 100
// coffee: 180
// juice: 150

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

  1. ['tea' => 120, 'coffee' => 180] создаёт массив из двух пар: слева от => стоит ключ, справа — значение.
  2. $prices['juice'] = 150; добавляет новую пару, потому что ключа 'juice' в массиве ещё нет.
  3. $prices['tea'] = 100; находит существующий ключ 'tea' и заменяет его значение.
  4. $prices['coffee'] читает значение по ключу и печатает 180, а count считает пары: их 3.
  5. foreach ($prices as $drink => $price) проходит по парам: в $drink попадает ключ, в $price — копия значения.

Порядок пар

Массив помнит порядок, в котором в него добавляли пары, и foreach обходит их именно так: tea, coffee, juice. Замена значения порядок не меняет. Ключ 'tea' получил новую цену 100, но остался первым.

Здесь картинка с гардеробом расходится с PHP. В театре крючки висят на стене в одном порядке раз и навсегда, а массив запоминает, в каком порядке вещи сдавали. Новая пара всегда встаёт в конец.

Удалить пару: unset

unset снимает пару целиком: ключа больше нет, и count уменьшается на один.

PHP
unset($prices['coffee']);
echo count($prices), ' ', implode(' ', $prices), "\n"; // 2 100 150

После unset в массиве две пары, tea и juice, а implode склеивает их значения: 100 150. Удалённую пару не видят ни count, ни implode, ни foreach.

Есть ли ключ: isset и array_key_exists

Перед чтением ключ часто проверяют, чтобы не получить Warning: Undefined array key. Для этого есть две проверки, и они отвечают на разные вопросы.

isset

Как вы уже знаете, isset отвечает true, если значение есть и не равно null. С элементом массива он работает так же: isset($prices['tea']) проверяет элемент и не выдаёт предупреждения, если ключа нет.

array_key_exists

array_key_exists('tea', $prices) спрашивает только одно: есть ли в массиве такой ключ. Что лежит под ним, функцию не интересует.

Разница видна, когда под ключом лежит null:

PHP
$phones = ['anna' => '555-01', 'boris' => null];
var_dump(isset($phones['boris'])); // bool(false)
var_dump(array_key_exists('boris', $phones)); // bool(true)
var_dump(isset($phones['vera'])); // bool(false)

Бирка boris висит, но вешалка под ней пустая. isset отвечает «вещи нет», а array_key_exists — «бирка есть». Для 'vera' нет даже бирки, и обе проверки дают false.

Чем isset отличается от array_key_exists, часто спрашивают на собеседовании. Ответ:

  • isset($a['k']) даёт true, только если ключ есть и значение под ним не null;
  • array_key_exists('k', $a) даёт true, если ключ есть, даже со значением null.

Один тип на всё

Список и ассоциативный массив в PHP — не два разных типа, а один. Любой массив хранит пары «ключ — значение» в порядке добавления. Ключами списка служат номера 0, 1, 2, которые PHP раздал сам, а ключи ассоциативного массива выбираете вы.

Поэтому foreach с => работает и для списка: ключом будет индекс. А в список можно дописать строковый ключ: после $list['main'] = 'blue' в массиве ['red', 'green'] окажутся три пары с ключами 0, 1 и 'main'.

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

Ключ написали без кавычек:

PHP
echo $prices[tea], "\n"; // ✗
TEXT
Fatal error: Uncaught Error: Undefined constant "tea"

Без кавычек tea — не строка, а имя константы. Такой константы в программе нет, и PHP останавливает скрипт на этой строке. Строковый ключ всегда пишут в кавычках: $prices['tea'].

Главное

  • Ассоциативный массив хранит пары «ключ — значение»: ['tea' => 120], а значение читают по ключу, $prices['tea'].
  • Запись в новый ключ добавляет пару в конец, в существующий — меняет значение на месте; unset удаляет пару целиком.
  • foreach ($a as $k => $v) обходит пары в порядке добавления; список — тот же массив с ключами 0, 1, 2.
  • isset($a['k']) даёт false и для ключа со значением null, а array_key_exists проверяет только ключ.