Массивы
Массив в PHP — это упорядоченная структура данных, которая связывает
значения и ключи.
Этот тип данных оптимизирован для разных целей, поэтому с ним работают
как с массивом, списком (вектором), хеш-таблицей (реализацией карты), словарём,
коллекцией, стеком, очередью и, возможно, чем-то ещё. Поскольку значениями массива бывают
другие массивы, также доступны деревья и многомерные массивы.
Объяснение этих структур данных выходит за рамки этого
руководства, но как минимум один пример будет приведён
для каждой из них. За дополнительной информацией обращаются
к большому объему литературы по этой обширной теме.
СинтаксисОпределение при помощи array
Массив (array) создают языковой конструкцией array.
В качестве аргументов она принимает любое количество разделённых запятыми пар
ключ => значение.
array(
key => value,
key2 => value2,
key3 => value3,
...
)
Запятая после последнего элемента массива необязательна и её можно опустить.
Обычно это делается для однострочных массивов, — лучше предпочесть array(1, 2)
вместо array(1, 2, ). Для многострочных массивов, наоборот,
обычно указывают висящую запятую, так как упрощает добавление
новых элементов в конец массива.
Существует короткий синтаксис массива, который заменяет
языковую конструкцию array() выражение [].
Простой массив
"bar",
"bar" => "foo",
);
// Работа с коротким синтаксисом массива
$array = [
"foo" => "bar",
"bar" => "foo",
];
?>
]]>
Ключ массива (key) разрешено указывать либо как целочисленное значение (int),
либо как строку (string).
Значение массива (value) может принадлежать любому типу данных.
Дополнительно произойдут следующие преобразования ключа key:
Строки (string), содержащие целое число (int)
(исключая случаи, когда перед числом указывают знак +),
будут преобразованы в целое число (int).
Например, ключ со значением «8» сохранится
со значением 8. При этом, значение «08»
не преобразуется, так как оно — не корректное десятичное целое.
Числа с плавающей точкой (float) также преобразуются
в целочисленные значения (int) — дробная часть будет отброшена.
Например, ключ со значением
8.7 будет сохранится со значением 8.
Логический тип (bool) также преобразовывается в целочисленный тип (int).
Например, ключ со значением &true; сохранится со значением
1, а ключ со значением &false; сохранится
со значением 0.
Тип null преобразуется в пустую строку. Например, ключ со
значением null сохранится со значением
"".
Массивы (array) и объекты (object) нельзя
указывать как ключи. Это
сгенерирует предупреждение: Недопустимый тип смещения (Illegal offset type).
Если нескольким элементам в объявлении массива указан одинаковый ключ, то только
последний будет сохранён, а другие будут перезаписаны.
Пример преобразования типов и перезаписи элементов
"a",
"1" => "b",
1.5 => "c",
true => "d",
);
var_dump($array);
?>
]]>
&example.outputs;
string(1) "d"
}
]]>
Поскольку все ключи в приведённом примере преобразуются к 1,
значение будет перезаписано на каждый новый элемент и останется только последнее
присвоенное значение — «d».
PHP разрешает массивам содержать одновременно
целочисленные (int)
и строковые (string) ключи, поскольку
PHP одинаково воспринимает индексные и ассоциативные массивы.
Смешанные целочисленные (int) и строковые (string) ключи
"bar",
"bar" => "foo",
100 => -100,
-100 => 100,
);
var_dump($array);
?>
]]>
&example.outputs;
string(3) "bar"
["bar"]=>
string(3) "foo"
[100]=>
int(-100)
[-100]=>
int(100)
}
]]>
Ключ (key) — необязателен. Если он не указан,
PHP инкрементирует предыдущее наибольшее целочисленное (int) значение ключа.
Индексные массивы без ключа
]]>
&example.outputs;
string(3) "foo"
[1]=>
string(3) "bar"
[2]=>
string(5) "hallo"
[3]=>
string(5) "world"
}
]]>
Разрешено указывать ключ одним элементам и пропускать для других:
Ключи для некоторых элементов
"c",
"d",
);
var_dump($array);
?>
]]>
&example.outputs;
string(1) "a"
[1]=>
string(1) "b"
[6]=>
string(1) "c"
[7]=>
string(1) "d"
}
]]>
Видно, что последнее значение «d» присвоилось ключу
7. Это произошло потому, что перед этим
самым большим значением целочисленного ключа было 6.
Расширенный пример преобразования типов и перезаписи элементов
'a',
'1' => 'b', // значение «b» перезапишет значение «a»
1.5 => 'c', // значение «c» перезапишет значение «b»
-1 => 'd',
'01' => 'e', // поскольку это не целочисленная строка, она НЕ перезапишет ключ 1
'1.5' => 'f', // поскольку это не целочисленная строка, она НЕ перезапишет ключ 1
true => 'g', // значение «g» перезапишет значение «c»
false => 'h',
'' => 'i',
null => 'j', // значение «j» перезапишет значение «i»
'k', // значение «k» присваивается ключу 2. Потому что самый большой целочисленный ключ до этого был 1
2 => 'l', // значение «l» перезапишет значение «k»
);
var_dump($array);
?>
]]>
&example.outputs;
string(1) "g"
[-1]=>
string(1) "d"
["01"]=>
string(1) "e"
["1.5"]=>
string(1) "f"
[0]=>
string(1) "h"
[""]=>
string(1) "j"
[2]=>
string(1) "l"
}
]]>
Этот пример включает все вариации преобразования ключей и перезаписи элементов
Доступ к элементам массива через синтаксис квадратных скобок
Доступ к элементам массива разрешено получать, используя синтакс array[key].
Доступ к элементам массива
"bar",
42 => 24,
"multi" => array(
"dimensional" => array(
"array" => "foo"
)
)
);
var_dump($array["foo"]);
var_dump($array[42]);
var_dump($array["multi"]["dimensional"]["array"]);
?>
]]>
&example.outputs;
До PHP 8.0.0 квадратные и фигурные скобки могли взаимозаменяться при доступе
к элементам массива (например, в приведённом примере $array[42] и $array{42}
делали одно и то же).
Синтаксис фигурных скобок устарел с PHP 7.4.0
и больше не поддерживается с PHP 8.0.0.
Разыменование массива
]]>
Попытка доступа к неопределённому ключу в массиве — это то же самое,
что и попытка доступа к любой другой неопределённой переменной:
будет выдана ошибка уровня E_WARNING
(ошибка уровня E_NOTICE до PHP 8.0.0),
и результат будет равен &null;.
Попытка разыменовать не массив, а скалярное значение, которое отличается от строки (string), отдаст &null;,
тогда как разыменовывание строки (string) трактует её как индексный массив.
При такой попытке до PHP 7.4.0 не выдавалось сообщение об ошибке.
С PHP 7.4.0 выдаётся ошибка уровня E_NOTICE;
с PHP 8.0.0 выдаётся ошибка уровня E_WARNING.
Создание и модификация с применением синтаксиса квадратных скобок
Разработчик может изменять существующий массив явной установкой значений.
Это делается путём присвоения значений массиву (array) с указанием ключа
в квадратных скобках. Кроме того, если опустить ключ, получится пустая пара скобок ([]).
$arr[key] = value;
$arr[] = value;
// Ключ key может принадлежать типу int или string
// Значение value может быть любым значением любого типа
Если массив $arr ещё не существует или для него
задано значение &null; или &false;, он будет создан.
Таким образом, это ещё один способ определить массив array. Однако такой
способ применять не рекомендовано, так как если переменная $arr
уже содержит значение (например, строку (string)
из переменной запроса), то это значение останется на месте и выражение [] может
означать доступ к символу в
строке. Лучше инициализировать переменную явным присваиванием значения.
Начиная с PHP 7.1.0 оператор пустого индекса на строке выбросит
фатальную ошибку. Раньше строка молча преобразовывалась в массив.
С PHP 8.1.0 способ, которым создавали новый массив приведением к нему значения &false;, устарел.
Способ, которым создают новый массив приведением к нему значения &null; и неопределённого значения, по-прежнему доступен.
Для изменения конкретного значения элементу просто присваивают новое значение,
указывая его ключ. Если нужно удалить пару ключ/значение, необходимо
вызывать конструкцию unset.
1, 12 => 2);
$arr[] = 56; // В этом месте скрипта это
// то же самое, что и $arr[13] = 56;
$arr["x"] = 42; // Это добавляет в массив новый
// элемент с ключом «x»
unset($arr[5]); // Это удаляет элемент из массива
unset($arr); // Это удаляет весь массив
?>
]]>
Как было сказано ранее, если разработчик не указал ключ, то будет взят максимальный
из существующих целочисленных (int) индексов, и новым ключом будет
это максимальное значение (в крайнем случае 0) плюс 1. Если целочисленных (int) индексов
ещё нет, то ключом будет 0 (ноль).
Учитывают, что максимальное целое значение ключа не обязательно
существует в массиве в текущий момент. Оно могло существовать
в массиве какое-то время с момента последней переиндексации.
Следующий пример это иллюстрирует:
$value) {
unset($array[$i]);
}
print_r($array);
// Добавляем элемент (обратите внимание, что новым ключом будет 5, а не 0).
$array[] = 6;
print_r($array);
// Переиндексация:
$array = array_values($array);
$array[] = 7;
print_r($array);
?>
]]>
&example.outputs;
1
[1] => 2
[2] => 3
[3] => 4
[4] => 5
)
Array
(
)
Array
(
[5] => 6
)
Array
(
[0] => 6
[1] => 7
)
]]>
Деструктуризация массива
Массивы разрешено деструктурировать языковыми конструкциями [] (начиная с PHP 7.1.0)
или list. Эти языковые конструкции разрешено использовать
для деструктуризации массива на отдельные переменные.
]]>
Деструктуризацию массива также выполняют в конструкции &foreach;
для деструктуризации многомерного массива во время итерации по массиву.
]]>
Элементы массива будут проигнорированы, если переменная не указана.
Деструктуризация массива начинается с индекса 0.
]]>
С PHP 7.1.0 ассоциативные массивы также разрешено деструктурировать.
Это упрощает выбор нужного элемента в массивах с числовым индексом,
так как индекс может быть указан явно.
1, 'bar' => 2, 'baz' => 3];
// Присваивание элемента с индексом «baz» переменной $three
['baz' => $three] = $source_array;
echo $three; // выведет 3
$source_array = ['foo', 'bar', 'baz'];
// Присваивание элемента с индексом 2 переменной $baz
[2 => $baz] = $source_array;
echo $baz; // выведет «baz»
?>
]]>
Деструктуризацией массив пользуются, чтобы поменять две переменные местами.
]]>
Оператор ... не поддерживается в присваиваниях.
Попытка получить доступ к неопределённому ключу массива
аналогична обращению к любой другой неопределённой переменной:
будет выдано сообщение об ошибке уровня E_WARNING
(ошибки уровня E_NOTICE до PHP 8.0.0),
а результатом будет значение &null;.
Полезные функции
Для работы с массивами есть довольного много полезных функций.
Подробнее об этом рассказано в разделе «Функции для работы с массивами».
Языковая конструкция unset умеет удалять ключи массива.
Обратите внимание, что массив НЕ
будет переиндексирован. Если нужно поведение в стиле
«удалить и сдвинуть», можно переиндексировать массив
функцией array_values.
'один', 2 => 'два', 3 => 'три');
unset($a[2]);
/* даст массив, представленный так:
$a = array(1 => 'один', 3 => 'три');
а НЕ так:
$a = array(1 => 'один', 2 => 'три');
*/
$b = array_values($a);
// Теперь $b это array(0 => 'один', 1 => 'три')
?>
]]>
Управляющая конструкция &foreach; существует специально для массивов.
Она предлагает простой способ перебора массива.
Что можно и нельзя делать с массивамиПочему выражение $foo[bar] неверно?
Рекомендовано заключать в кавычки строковый литерал в индексе ассоциативного массива.
Например, нужно писать $foo['bar'], а не
$foo[bar]. Но почему? Часто в старых скриптах можно встретить
следующий синтаксис:
]]>
Это неверно, хотя и работает. Причина в том, что этот код содержит неопределённую
константу (bar), а не строку ('bar' — обратите внимание
на кавычки). Это работает, потому что PHP автоматически преобразовывает
«голую строку» (не заключённую в кавычки строку,
которая не соответствует ни одному из известных символов языка) в строку
со значением этой «голой строки». Например, если константа с именем bar
не определена, то PHP заменит bar на
строку «bar» и будет работать с ней.
Резервный вариант для обработки неопределённой константы как пустой строки
выдаёт ошибку уровня E_NOTICE.
Начиная с PHP 7.2.0 поведение объявлено устаревшим
и выдаёт ошибку уровня E_WARNING.
Начиная с PHP 8.0.0 удалено и выбрасывает исключение Error.
Это не значит, что нужно всегда заключать
ключ в кавычки. Не обязательно заключать в кавычки константы или переменные, поскольку это
помешает PHP обрабатывать их.
]]>
&example.outputs;
Дополнительные примеры, которые подтверждают этот факт:
'apple', 'veggie' => 'carrot');
// Верно
print $arr['fruit']; // apple
print $arr['veggie']; // carrot
// Неверно. Это работает, но из-за неопределённой константы с
// именем fruit также выдаёт ошибку PHP уровня E_NOTICE
//
// Notice: Use of undefined constant fruit - assumed 'fruit' in...
print $arr[fruit]; // apple
// Давайте определим константу, чтобы продемонстрировать, что
// происходит. Присвоим константе с именем fruit значение «veggie».
define('fruit', 'veggie');
// Теперь обратите внимание на разницу
print $arr['fruit']; // apple
print $arr[fruit]; // carrot
// Внутри строки это нормально. Внутри строк константы не
// рассматриваются, так что ошибки E_NOTICE здесь не произойдёт
print "Hello $arr[fruit]"; // Hello apple
// С одним исключением: фигурные скобки вокруг массивов внутри
// строк позволяют константам там находиться
print "Hello {$arr[fruit]}"; // Hello carrot
print "Hello {$arr['fruit']}"; // Hello apple
// Это не будет работать и вызовет ошибку обработки:
// Parse error: parse error, expecting T_STRING' or T_VARIABLE' or T_NUM_STRING'
// Это, конечно, также действует и с суперглобальными переменными в строках
print "Hello $arr['fruit']";
print "Hello $_GET['foo']";
// Ещё одна возможность — конкатенация
print "Hello " . $arr['fruit']; // Hello apple
?>
]]>
Если директива error_reporting настроена
на режим отображения ошибок уровня
E_NOTICE (например,
E_ALL), ошибки сразу будут видны.
По умолчанию директива
error_reporting настроена на то, чтобы не показывать предупреждения.
Как указано в разделе о синтаксисе,
внутри квадратных скобок («[»
и «]») должно быть выражение. То есть вот такой код работает:
]]>
Это пример работы с возвращаемым функцией значением
в качестве индекса массива. PHP также знает о константах:
]]>
Обратите внимание, что E_ERROR — это такой же
допустимый идентификатор, как и bar в первом примере.
Но последний пример по существу эквивалентен такой записи:
]]>
поскольку значение константы E_ERROR соответствует значению 1 и т. д.
Так что же в этом плохого?
Когда-нибудь в будущем команда разработчиков PHP, возможно, захочет
добавить ещё одну константу или ключевое слово, либо константа из
другого кода может вмешаться.
Например, неправильно использовать
слова empty и
default, поскольку они относятся к
зарезервированным ключевым словам.
Повторим, внутри строки (string)
в двойных кавычках допустимо не окружать индексы
массива кавычками, поэтому «$foo[bar]» —
допустимая запись. В примерах выше объяснено, почему,
дополнительная информация дана в разделе
об обработке
переменных в строках.
Преобразование в массив
Преобразование целого числа (int), числа с плавающей точкой (float),
строки (string), логического значения (bool) или ресурса (resource)
в массив — создаёт массив
с одним элементом с индексом 0 и значением скаляра, который
был преобразован. Говоря по-другому, выражение (array) $scalarValue
аналогично выражению array($scalarValue).
Если объект (object) будет преобразован в массив,
элементами массива будут свойства (переменные-члены)
этого объекта. Ключами будут имена переменных-членов, со следующими примечательными
исключениями: целочисленные свойства станут недоступны;
к закрытым полям класса (private) в начало будет дописано имя класса;
к защищённым полям класса (protected) в начало будет добавлен символ '*'.
Эти добавленные с обоих сторон значения также получат NUL-байты.
Неинициализированные типизированные свойства
автоматически отбрасываются.
{1} = null;
}
}
var_export((array) new A());
?>
]]>
&example.outputs;
NULL,
'' . "\0" . '*' . "\0" . 'C' => NULL,
'D' => NULL,
1 => NULL,
)
]]>
Это может вызвать несколько неожиданное поведение:
]]>
&example.outputs;
NULL
["AA"]=>
NULL
["AA"]=>
NULL
}
]]>
Приведённый код покажет 2 ключа с именем «AA», хотя один из них на самом деле
имеет имя «\0A\0A».
Если преобразовать в массив значение &null;, получится
пустой массив.
Сравнение
Массивы сравнивают функцией array_diff
и операторами массивов.
Распаковка массива
Массив, перед которым указан оператор ..., будет распакован во время определения массива.
Только массивы и объекты, которые реализуют интерфейс
Traversable, разрешено распаковывать.
Распаковка массива оператором ... доступна начиная с PHP 7.4.0.
Массив разрешено распаковывать несколько раз и добавлять обычные элементы до или после оператора ...:
Простая распаковка массива
'd']; // ['a', 'b', 'c' => 'd']
?>
]]>
Распаковка массива оператором ... соблюдает семантику функции array_merge.
То есть более поздние строковые ключи перезаписывают более ранние, а целочисленные ключи перенумеровываются:
Распаковка массива с дублирующим ключом
1];
$arr2 = ["a" => 2];
$arr3 = ["a" => 0, ...$arr1, ...$arr2];
var_dump($arr3); // ["a" => 2]
// целочисленный ключ
$arr4 = [1, 2, 3];
$arr5 = [4, 5, 6];
$arr6 = [...$arr4, ...$arr5];
var_dump($arr6); // [1, 2, 3, 4, 5, 6]
// Который [0 => 1, 1 => 2, 2 => 3, 3 => 4, 4 => 5, 5 => 6]
// где исходные целочисленные ключи не были сохранены.
?>
]]>
Ключи, тип которых не принадлежит ни целыми числами, ни строками,
выбрасывают исключение TypeError.
Такие ключи генерируются только объектом Traversable.
До PHP 8.1 распаковка массива со строковым ключом не поддерживалась:
4];
$arr3 = [...$arr1, ...$arr2];
// Fatal error: Uncaught Error: Cannot unpack array with string keys in example.php:5
$arr4 = [1, 2, 3];
$arr5 = [4, 5];
$arr6 = [...$arr4, ...$arr5]; // работает. [1, 2, 3, 4, 5]
?>
]]>
Примеры
Массив в PHP — гибкий тип данных. Вот несколько примеров:
'красный',
'taste' => 'сладкий',
'shape' => 'круг',
'name' => 'яблоко',
4 // ключом будет 0
);
$b = array('a', 'b', 'c');
// ...эквивалентен этому:
$a = array();
$a['color'] = 'красный';
$a['taste'] = 'сладкий';
$a['shape'] = 'круг';
$a['name'] = 'яблоко';
$a[] = 4; // ключом будет 0
$b = array();
$b[] = 'a';
$b[] = 'b';
$b[] = 'c';
// после выполнения приведённого кода, переменная $a будет массивом
// array('color' => 'красный', 'taste' => 'сладкий', 'shape' => 'круг',
// 'name' => 'яблоко', 0 => 4), а переменная $b будет
// array(0 => 'a', 1 => 'b', 2 => 'c'), или просто array('a', 'b', 'c').
?>
]]>
Вызов языковой конструкции array()
4,
'OS' => 'Linux',
'lang' => 'english',
'short_tags' => true
);
// строго числовые ключи
$array = array(
7,
8,
0,
156,
-10
);
// это то же самое, что и array(0 => 7, 1 => 8, ...)
$switching = array(
10, // ключ = 0
5 => 6,
3 => 7,
'a' => 4,
11, // ключ = 6 (максимальным числовым индексом было 5)
'8' => 2, // ключ = 8 (число!)
'02' => 77, // ключ = '02'
0 => 12 // значение 10 будет перезаписано на 12
);
// пустой массив
$empty = array();
?>
]]>
Коллекция
]]>
&example.outputs;
Непосредственное изменение значений массива
допустимо через передачу значений по ссылке.
Изменение элемента в цикле
]]>
&example.outputs;
КРАСНЫЙ
[1] => ГОЛУБОЙ
[2] => ЗЕЛЁНЫЙ
[3] => ЖЁЛТЫЙ
)
]]>
Следующий пример создаёт массив, индексация которого начинается с единицы.
Индекс, начинающийся с единицы
'Январь', 'Февраль', 'Март');
print_r($firstquarter);
?>
]]>
&example.outputs;
'Январь'
[2] => 'Февраль'
[3] => 'Март'
)
]]>
Заполнение массива
]]>
Массивы упорядочены. Порядок изменяют
разными функциями сортировки. Подробнее об этом рассказано
в разделе «Функции
для работы с массивами». Для подсчёта количества элементов
в массиве вызывают функцию count.
Сортировка массива
]]>
Поскольку значению массива разрешено быть любым,
значение может быть также другим массивом. Поэтому разрешено создавать
рекурсивные и многомерные массивы.
Рекурсивные и многомерные массивы
array ( "a" => "апельсин",
"b" => "банан",
"c" => "яблоко"
),
"numbers" => array ( 1,
2,
3,
4,
5,
6
),
"holes" => array ( "первая",
5 => "вторая",
"третья"
)
);
// Несколько примеров доступа к значениям предыдущего массива
echo $fruits["holes"][5]; // напечатает «вторая»
echo $fruits["fruits"]["a"]; // напечатает «апельсин»
unset($fruits["holes"][0]); // удалит «первая»
// Создаст новый многомерный массив
$juices["apple"]["green"] = "хороший";
?>
]]>
Присваивание массива включает копирование значения. Чтобы скопировать массив
по ссылке, указывают оператор присваивания по ссылке.
]]>