Ассоциативные массивы
В прошлом уроке вещи висели на крючках с номерами. Но номер ничего не говорит о вещи: под каким номером в меню кафе чай — 0 или 2? Удобнее, когда у каждой вещи есть понятное имя.
Представьте, что в гардеробе вместо номерков выдают бирки с именами. Пальто Анны висит под биркой anna, куртка Бориса — под биркой boris. Чтобы забрать вещь, достаточно назвать имя.
Массив, в котором значения находят не по номеру, а по имени, называют ассоциативным массивом. То, по чему находят значение, называют ключом: в списке это номер, в ассоциативном массиве — имя. Вот меню кафе, где ключом служит название напитка, а значением — цена:
<?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Давайте разберём по строкам:
['tea' => 120, 'coffee' => 180]создаёт массив из двух пар: слева от=>стоит ключ, справа — значение.$prices['juice'] = 150;добавляет новую пару, потому что ключа'juice'в массиве ещё нет.$prices['tea'] = 100;находит существующий ключ'tea'и заменяет его значение.$prices['coffee']читает значение по ключу и печатает180, аcountсчитает пары: их3.foreach ($prices as $drink => $price)проходит по парам: в$drinkпопадает ключ, в$price— копия значения.
Порядок пар
Массив помнит порядок, в котором в него добавляли пары, и foreach обходит их именно так: tea, coffee, juice. Замена значения порядок не меняет. Ключ 'tea' получил новую цену 100, но остался первым.
Здесь картинка с гардеробом расходится с PHP. В театре крючки висят на стене в одном порядке раз и навсегда, а массив запоминает, в каком порядке вещи сдавали. Новая пара всегда встаёт в конец.
Удалить пару: unset
unset снимает пару целиком: ключа больше нет, и count уменьшается на один.
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:
$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'.
Частая ошибка
Ключ написали без кавычек:
echo $prices[tea], "\n"; // ✗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проверяет только ключ.