1
0
mirror of https://github.com/php/doc-ru.git synced 2026-03-23 23:32:16 +01:00
Files
archived-doc-ru/language/types/array.xml
2025-12-26 13:23:38 +03:00

1568 lines
54 KiB
XML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?xml version="1.0" encoding="utf-8"?>
<!-- EN-Revision: 3061900171d4ae84d532571bfd6eda823726dad4 Maintainer: shein Status: ready -->
<!-- Reviewed: no -->
<sect1 xml:id="language.types.array">
<title>Массивы</title>
<para>
Список функций для работы с массивами доступен в главе документации «<link linkend="ref.array">Функции для работы с массивами</link>».
</para>
<para>
Массив в PHP — упорядоченная структура данных, которая связывает
<emphasis>значения</emphasis> и <emphasis>ключи</emphasis>.
Этот тип данных оптимизирован для разных целей, поэтому с ним работают
как с массивом, списком (вектором), хеш-таблицей (реализацией карты), словарём,
коллекцией, стеком, очередью и, возможно, чем-то ещё. Поскольку значениями массива бывают
другие массивы, также доступны деревья и многомерные массивы.
</para>
<para>
Объяснение структур данных выходит за рамки
руководства, но как минимум один пример приводится
для каждой из них. За дополнительной информацией обращаются
к большому объему литературы по этой обширной теме.
</para>
<sect2 xml:id="language.types.array.syntax">
<title>Синтаксис</title>
<sect3 xml:id="language.types.array.syntax.array-func">
<title>Определение массива через языковую конструкцию <function>array</function></title>
<para>
Массив (<type>array</type>) создают языковой конструкцией <function>array</function>.
Конструкция принимает как аргументы произвольное количество разделённых запятыми пар
<literal><replaceable>ключ</replaceable> =&gt; <replaceable>значение</replaceable></literal>.
</para>
<synopsis>
array(
<optional><replaceable>key</replaceable> =&gt; </optional><replaceable>value</replaceable>,
<optional><replaceable>key2</replaceable> =&gt; </optional><replaceable>value2</replaceable>,
<optional><replaceable>key3</replaceable> =&gt; </optional><replaceable>value3</replaceable>,
...
)</synopsis>
<!-- Do not fix the whitespace for the synopsis end element. A limitation of PhD prevents proper trimming -->
<para>
Запятая после последнего элемента массива необязательна; пропуск конечной запятой не вызывает ошибок.
Конечную запятую часто опускают в определениях однострочных массивов, — лучше предпочесть <literal>array(1, 2)</literal>
вместо <literal>array(1, 2, )</literal>. Для многострочных массивов, наоборот,
часто указывают конечную запятую, поскольку это упрощает добавление
новых элементов в конец массива.
</para>
<note>
<para>
PHP поддерживает короткий синтаксис массива, который заменяет
языковую конструкцию <literal>array()</literal> выражением <literal>[]</literal>.
</para>
</note>
<example>
<title>Простой массив</title>
<programlisting role="php">
<![CDATA[
<?php
$array1 = array(
"foo" => "bar",
"bar" => "foo",
);
// Работа с коротким синтаксисом массива
$array2 = [
"foo" => "bar",
"bar" => "foo",
];
var_dump($array1, $array2);
]]>
</programlisting>
</example>
<para>
В PHP массивы поддерживают только целочисленные (<type>int</type>)
и строковые (<type>string</type>) <replaceable>ключи</replaceable>.
Тип <replaceable>значений</replaceable> не ограничивается.
</para>
<para xml:id="language.types.array.key-casts">
Дополнительно выполняются следующие преобразования <replaceable>ключа</replaceable>:
<itemizedlist>
<listitem>
<simpara>
Строки (<type>string</type>), которые содержат целое число (<type>int</type>),
преобразуются в значение <type>int</type>,
если только перед числом не указали знак <literal>+</literal>.
Например, ключ со значением <literal>"8"</literal> сохранится
со значением <literal>8</literal>. При этом значение <literal>"08"</literal>
не преобразуется, поскольку не относится к корректным десятичным целым.
</simpara>
</listitem>
<listitem>
<simpara>
Числа с плавающей точкой (<type>float</type>) также преобразуются
в целочисленные значения <type>int</type> — дробная часть отбрасывается.
Например, ключ со значением
<literal>8.7</literal> сохранится как <literal>8</literal>.
</simpara>
</listitem>
<listitem>
<simpara>
Значения с типом <type>bool</type> также преобразуются в целочисленный тип <type>int</type>.
Например, ключ со значением &true; сохранится как <literal>1</literal>,
а ключ со значением &false; — как <literal>0</literal>.
</simpara>
</listitem>
<listitem>
<simpara>
Тип <type>null</type> преобразуется в пустую строку. Например,
ключ со значением <literal>null</literal> сохранится как <literal>""</literal>.
</simpara>
</listitem>
<listitem>
<simpara>
Массивы (<type>array</type>) и объекты (<type>object</type>) <emphasis>нельзя</emphasis>
указывать как ключи. Это сгенерирует предупреждение: <literal>Illegal offset type</literal>.
</simpara>
</listitem>
</itemizedlist>
</para>
<para>
PHP перезаписывает значение элемента, если встречает в объявлении массива
повтор одного и того же ключа, поэтому в массиве остается только последний такой элемент.
</para>
<example>
<title>Преобразование типов и перезапись элементов</title>
<programlisting role="php">
<![CDATA[
<?php
$array = array(
1 => "a",
"1" => "b",
1.5 => "c",
true => "d",
);
var_dump($array);
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
array(1) {
[1]=>
string(1) "d"
}
]]>
</screen>
<para>
Поскольку каждый ключ в этом примере приводится к <literal>1</literal>,
значение перезаписывается на каждом новом элементе, и останется единственное
значение <literal>"d"</literal>, которое присвоилось последним.
</para>
</example>
<para>
PHP разрешает массивам содержать одновременно
целочисленные (<type>int</type>)
и строковые (<type>string</type>) ключи, поскольку
PHP одинаково воспринимает индексные и ассоциативные массивы.
</para>
<example>
<title>Смешанные целочисленные (<type>int</type>) и строковые (<type>string</type>) ключи</title>
<programlisting role="php">
<![CDATA[
<?php
$array = array(
"foo" => "bar",
"bar" => "foo",
100 => -100,
-100 => 100,
);
var_dump($array);
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
array(4) {
["foo"]=>
string(3) "bar"
["bar"]=>
string(3) "foo"
[100]=>
int(-100)
[-100]=>
int(100)
}
]]>
</screen>
</example>
<para>
<replaceable>Ключ</replaceable> необязателен: ключом нового элемента, для которого не указали ключ,
станет увеличенный на единицу предыдущий наибольший целочисленный (<type>int</type>) ключ.
</para>
<example>
<title>Индексные массивы без ключа</title>
<programlisting role="php">
<![CDATA[
<?php
$array = array("foo", "bar", "hallo", "world");
var_dump($array);
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
array(4) {
[0]=>
string(3) "foo"
[1]=>
string(3) "bar"
[2]=>
string(5) "hallo"
[3]=>
string(5) "world"
}
]]>
</screen>
</example>
<para>
Разрешено указывать ключ одним элементам и пропускать для других:
</para>
<example>
<title>Ключи для некоторых элементов</title>
<programlisting role="php">
<![CDATA[
<?php
$array = array(
"a",
"b",
6 => "c",
"d",
);
var_dump($array);
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
array(4) {
[0]=>
string(1) "a"
[1]=>
string(1) "b"
[6]=>
string(1) "c"
[7]=>
string(1) "d"
}
]]>
</screen>
<para>
Видно, что последнее значение <literal>"d"</literal> присвоилось ключу
<literal>7</literal>. Это произошло потому, что перед этим
самым большим значением целочисленного ключа было <literal>6</literal>.
</para>
</example>
<example>
<title>Расширенный пример преобразования типов и перезаписи элементов</title>
<para>
Приведённый пример показывает все приведения типов ключей и перезаписи элементов.
</para>
<programlisting role="php">
<![CDATA[
<?php
$array = array(
1 => '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);
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
array(7) {
[1]=>
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"
}
]]>
</screen>
</example>
<example>
<title>Отрицательные индексы</title>
<simpara>
При назначении отрицательного целочисленного ключа <literal>n</literal>,
PHP позаботится о том, чтобы назначить следующий ключ <literal>n + 1</literal>.
</simpara>
<programlisting role="php">
<![CDATA[
<?php
$array = [];
$array[-5] = 1;
$array[] = 2;
var_dump($array);
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
array(2) {
[-5]=>
int(1)
[-4]=>
int(2)
}
]]>
</screen>
<warning>
<simpara>
До PHP 8.3.0 назначение отрицательного целочисленного ключа <literal>n</literal>
присвоило бы следующему ключу значение <literal>0</literal>, поэтому приведённый пример
вывел бы:
</simpara>
<informalexample>
<screen>
<![CDATA[
array(2) {
[-5]=>
int(1)
[0]=>
int(2)
}
]]>
</screen>
</informalexample>
</warning>
</example>
</sect3>
<sect3 xml:id="language.types.array.syntax.accessing">
<title>Доступ к элементам массива через синтаксис квадратных скобок</title>
<para>
Доступ к элементам массива получают синтаксисом <literal>array[key]</literal>.
</para>
<example>
<title>Доступ к элементам массива</title>
<programlisting role="php">
<![CDATA[
<?php
$array = array(
"foo" => "bar",
42 => 24,
"multi" => array(
"dimensional" => array(
"array" => "foo"
)
)
);
var_dump($array["foo"]);
var_dump($array[42]);
var_dump($array["multi"]["dimensional"]["array"]);
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
string(3) "bar"
int(24)
string(3) "foo"
]]>
</screen>
</example>
<note>
<para>
До PHP 8.0.0 квадратные и фигурные скобки могли взаимозаменяться при доступе
к элементам массива (например, в приведённом примере <literal>$array[42]</literal> и <literal>$array{42}</literal>
делали одно и то же).
Синтаксис фигурных скобок устарел с PHP 7.4.0
и больше не поддерживается с PHP 8.0.0.
</para>
</note>
<example>
<title>Разыменование массива</title>
<programlisting role="php">
<![CDATA[
<?php
function getArray()
{
return array(1, 2, 3);
}
$secondElement = getArray()[1];
var_dump($secondElement);
]]>
</programlisting>
</example>
<note>
<para>
Попытка доступа к неопределённому ключу в массиве — то же,
что и попытка доступа к неопределённой переменной:
выдаётся ошибка уровня <constant>E_WARNING</constant>
или до PHP 8.0.0 ошибка уровня <constant>E_NOTICE</constant>,
и результат равняется &null;.
</para>
</note>
<note>
<para>
Попытка разыменовать не массив, а скалярное значение, которое отличается от строки (<type>string</type>), отдаст &null;,
тогда как разыменование значения <type>string</type> трактует строку как индексный массив.
При такой попытке до PHP 7.4.0 не выдавалось сообщение об ошибке.
С PHP 7.4.0 выдаётся ошибка уровня <constant>E_NOTICE</constant>;
с PHP 8.0.0 выдаётся ошибка уровня <constant>E_WARNING</constant>.
</para>
</note>
</sect3>
<sect3 xml:id="language.types.array.syntax.modifying">
<title>Создание или модификация массива синтаксисом квадратных скобок</title>
<para>
Массив возможно изменить путём явной установки значений.
</para>
<para>
Присваивание через ключ в квадратных скобках установит значение массива (<type>array</type>),
а пара пустых скобок <literal>[]</literal> добавит новое значение.
</para>
<synopsis>
$arr[<replaceable>key</replaceable>] = <replaceable>value</replaceable>;
$arr[] = <replaceable>value</replaceable>;
// В ключе <replaceable>key</replaceable> указывают только значения типов <type>int</type> или <type>string</type>,
// а в элементе <replaceable>value</replaceable> — значения произвольного типа
</synopsis>
<para>
PHP создаст новый массив, если переменную <varname>$arr</varname> ещё не определили
или присвоили переменной значение &null; или &false;,
так что это альтернативный способ создать массив <type>array</type>. Однако создавать
массив такими способом не рекомендуют, поскольку если переменная <varname>$arr</varname>
уже содержит значение наподобие <type>string</type>-переменной сетевого запроса,
это значение или не изменится и вызовет ошибку, или инструкция <literal>[]</literal>
интерпретируется как <link linkend="language.types.string.substr">оператор доступа к символу в строке</link>.
Лучше инициализировать переменную прямым присваиванием.
</para>
<note>
<simpara>
Начиная с PHP 7.1.0 оператор пустого индекса на строке выбросит
фатальную ошибку. Раньше строка молча преобразовывалась в массив.
</simpara>
</note>
<note>
<simpara>
С PHP 8.1.0 способ, которым создавали новый массив приведением к нему значения &false;, устарел.
Способ, которым создают новый массив приведением к нему значения &null; и неопределённого значения, по-прежнему доступен.
</simpara>
</note>
<para>
Для изменения конкретного значения указывают ключ элемента и присваивают новое значение.
Пару «ключ — значение» удаляют языковой конструкцией <function>unset</function>.
</para>
<example>
<title>Работа с массивами через квадратные скобки</title>
<programlisting role="php">
<![CDATA[
<?php
$arr = array(5 => 1, 12 => 2);
$arr[] = 56; // В этом месте скрипта такое аналогично
// присваиванию $arr[13] = 56;
$arr["x"] = 42; // Добавление в массив нового
// элемента с ключом "x"
unset($arr[5]); // Удаление элемента из массива
var_dump($arr);
unset($arr); // Конструкция удаляет весь массив
var_dump($arr);
]]>
</programlisting>
</example>
<note>
<para>
Как уже отмечалось, при добавлении в массив нового значения без указания ключа PHP присвоит новому элементу
целочисленный ключ на 1 больше текущего наибольшего целочисленного (<type>int</type>) индекса,
но не меньше 0. В массиве без целочисленных (<type>int</type>) индексов
новому элементу присваивается ключ <literal>0</literal> — ноль.
</para>
<para>
При работе с массивами учитывают, что наибольший целочисленный ключ, на основе которого вычисляется новый ключ,
<emphasis>не обязательно содержится в массиве в текущий момент</emphasis>.
PHP вычислит новый ключ на основе наибольшего целочисленного ключа,
который появлялся в массиве с момента последней переиндексации.
Следующий пример это иллюстрирует:
</para>
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
// Создаём простой массив.
$array = array(1, 2, 3, 4, 5);
print_r($array);
// Теперь удаляем каждый элемент, но массив оставляем нетронутым:
foreach ($array as $i => $value) {
unset($array[$i]);
}
print_r($array);
// Добавляем элемент (обратите внимание, что новым ключом станет 5, а не 0).
$array[] = 6;
print_r($array);
// Переиндексация:
$array = array_values($array);
$array[] = 7;
print_r($array);
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
[4] => 5
)
Array
(
)
Array
(
[5] => 6
)
Array
(
[0] => 6
[1] => 7
)
]]>
</screen>
</informalexample>
</note>
</sect3>
<sect3 xml:id="language.types.array.syntax.destructuring">
<title>Деструктуризация массива</title>
<para>
Массивы деструктурируют языковыми конструкциями <literal>[]</literal> (начиная с PHP 7.1.0)
или <function>list</function>. Эти языковые конструкции разрешено использовать
для деструктуризации массива на отдельные переменные.
</para>
<example>
<title>Деструктуризация массива</title>
<programlisting role="php">
<![CDATA[
<?php
$source_array = ['foo', 'bar', 'baz'];
[$foo, $bar, $baz] = $source_array;
echo $foo, PHP_EOL; // Выведет "foo"
echo $bar, PHP_EOL; // Выведет "bar"
echo $baz, PHP_EOL; // Выведет "baz"
]]>
</programlisting>
</example>
<para>
Деструктуризацию массива также выполняют в конструкции &foreach;
для деструктуризации многомерного массива во время итерации по массиву.
</para>
<example>
<title>Деструктуризация массива в конструкции foreach</title>
<programlisting role="php">
<![CDATA[
<?php
$source_array = [
[1, 'John'],
[2, 'Jane'],
];
foreach ($source_array as [$id, $name]) {
echo "{$id}: '{$name}'\n";
}
]]>
</programlisting>
</example>
<para>
Деструктуризация проигнорирует элементы массива, для которых не указали переменную.
Деструктуризация массива начинается с индекса <literal>0</literal>.
</para>
<example>
<title>Игнорирование элементов</title>
<programlisting role="php">
<![CDATA[
<?php
$source_array = ['foo', 'bar', 'baz'];
// Присваивание элемента с индексом 2 переменной $baz
[, , $baz] = $source_array;
echo $baz; // Выведет "baz"
]]>
</programlisting>
</example>
<para>
Начиная с PHP 7.1.0 поддерживается деструктуризация ассоциативных массивов.
Это упрощает выбор элемента в массивах с числовым индексом,
поскольку разрешает явно указать индекс.
</para>
<example>
<title>Деструктуризация ассоциативных массивов</title>
<programlisting role="php">
<![CDATA[
<?php
$source_array = ['foo' => 1, 'bar' => 2, 'baz' => 3];
// Присваивание элемента с индексом 'baz' переменной $three
['baz' => $three] = $source_array;
echo $three, PHP_EOL; // Выведет 3
$source_array = ['foo', 'bar', 'baz'];
// Присваивание элемента с индексом 2 переменной $baz
[2 => $baz] = $source_array;
echo $baz, PHP_EOL; // Выведет "baz"
]]>
</programlisting>
</example>
<para>
Массив деструктурируют, чтобы поменять две переменные местами.
</para>
<example>
<title>Перестановка двух переменных</title>
<programlisting role="php">
<![CDATA[
<?php
$a = 1;
$b = 2;
[$b, $a] = [$a, $b];
echo $a, PHP_EOL; // Выведет 2
echo $b, PHP_EOL; // Выведет 1
]]>
</programlisting>
</example>
<note>
<para>
Оператор <literal>...</literal> не поддерживается в присваиваниях.
</para>
</note>
<note>
<para>
Попытка получить доступ к неопределённому ключу массива
аналогична обращению к любой другой неопределённой переменной:
выдаётся сообщение об ошибке уровня <constant>E_WARNING</constant>,
или ошибки уровня <constant>E_NOTICE</constant> до PHP 8.0.0,
а результатом становится значение &null;.
</para>
</note>
<note>
<para>
Деструктуризация скалярного значения присваивает значение &null; каждой переменной в левой части выражения присваивания.
</para>
</note>
</sect3>
</sect2><!-- end syntax -->
<sect2 xml:id="language.types.array.useful-funcs">
<title>Полезные функции</title>
<para>
Для работы с массивами есть довольного много полезных функций.
Подробнее об этом рассказано в разделе «<link linkend="ref.array">Функции для работы с массивами</link>».
</para>
<note>
<para>
Языковая конструкция <function>unset</function> умеет удалять ключи массива.
Обратите внимание, что массив <emphasis>НЕ</emphasis>
переиндексируется. Массив переиндексируют функцией <function>array_values</function>,
если требуется поведение в стиле «удалить и сдвинуть».
</para>
<example>
<title>Удаление промежуточных элементов</title>
<programlisting role="php">
<![CDATA[
<?php
$a = array(1 => 'один', 2 => 'два', 3 => 'три');
/* Удаление элемента изменит массив так, как если бы его определили так:
$a = array(1 => 'один', 3 => 'три');
но НЕ так:
$a = array(1 => 'один', 2 => 'три');
*/
unset($a[2]);
var_dump($a);
$b = array_values($a);
// Теперь переменная $b содержит array(0 => 'один', 1 => 'три')
var_dump($b);
]]>
</programlisting>
</example>
</note>
<para>
Управляющая конструкция &foreach; появилась в языке для перебора массивов.
Конструкция предлагает простой способ обхода массива.
</para>
</sect2>
<sect2 xml:id="language.types.array.donts">
<title>Что можно и нельзя делать с массивами</title>
<sect3 xml:id="language.types.array.foo-bar">
<title>Почему выражение <literal>$foo[bar]</literal> неверно?</title>
<para>
Строковый литерал в индексе ассоциативного массива лучше брать в кавычки.
Например, правильно писать <literal>$foo['bar']</literal>,
а не <literal>$foo[bar]</literal>. Но почему? С старых скриптах часто встречается
следующий синтаксис:
</para>
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
$foo[bar] = 'враг';
echo $foo[bar];
// и т. д.
]]>
</programlisting>
</informalexample>
<para>
Неправильно записывать ключ без кавычек, хотя такой код и работает. Причина заключается в интерпретации незакавыченного ключа
как неопределённой константы <literal>bar</literal>, а не строки <literal>'bar'</literal> — литерала в кавычках.
Код работает из-за автоматического преобразования
<emphasis>«голой строки»</emphasis> — строки без кавычек,
которая не соответствует ни одному известному символу, — в строку
со значением такой «голой строки». PHP подставит вместо bar
строку <literal>'bar'</literal>,
если в текущей области видимости недоступна константа с названием <constant>bar</constant>.
</para>
<warning>
<simpara>
Резервный вариант для обработки неопределённой константы как пустой строки
выдаёт ошибку уровня <constant>E_NOTICE</constant>.
Начиная с PHP 7.2.0 поведение объявлено устаревшим
и выдаёт ошибку уровня <constant>E_WARNING</constant>.
Начиная с PHP 8.0.0 удалено и выбрасывает исключение <classname>Error</classname>.
</simpara>
</warning>
<simpara>
Это не значит, что в кавычки заключают <emphasis>каждый</emphasis> ключ.
В кавычки не берут <link linkend="language.constants">константы</link>
и <link linkend="language.variables">переменные</link>,
поскольку закавычивание помешает интерпретации.
</simpara>
<example>
<title>Закавычивание ключей</title>
<programlisting role="php">
<![CDATA[
<?php
error_reporting(E_ALL);
ini_set('display_errors', true);
ini_set('html_errors', false);
// Простой массив:
$array = array(1, 2);
$count = count($array);
for ($i = 0; $i < $count; $i++) {
echo "\nПроверяем $i: \n";
echo "Плохо: " . $array['$i'] . "\n";
echo "Хорошо: " . $array[$i] . "\n";
echo "Плохо: {$array['$i']}\n";
echo "Хорошо: {$array[$i]}\n";
}
]]>
</programlisting>
</example>
&example.outputs;
<screen>
<![CDATA[
Проверяем 0:
Notice: Undefined index: $i in /path/to/script.html on line 9
Плохо:
Хорошо: 1
Notice: Undefined index: $i in /path/to/script.html on line 11
Плохо:
Хорошо: 1
Проверяем 1:
Notice: Undefined index: $i in /path/to/script.html on line 9
Плохо:
Хорошо: 2
Notice: Undefined index: $i in /path/to/script.html on line 11
Плохо:
Хорошо: 2
]]>
</screen>
<para>
Дополнительные примеры, которые подтверждают этот факт:
</para>
<example>
<title>Дополнительные примеры</title>
<programlisting role="php">
<![CDATA[
<?php
// Показываем все ошибки
error_reporting(E_ALL);
$arr = array('fruit' => 'apple', 'veggie' => 'carrot');
// Верно
echo $arr['fruit'], PHP_EOL; // apple
echo $arr['veggie'], PHP_EOL; // carrot
// Неверно. Это не работает и выбрасывает PHP-ошибку Error из-за неопределённой константы
// с названием fruit
//
// Error: Undefined constant "fruit"
try {
echo $arr[fruit];
} catch (Error $e) {
echo get_class($e), ': ', $e->getMessage(), PHP_EOL;
}
// Определим константу и посмотрим,
// как изменится поведение кода. Присвоим константе с названием fruit значение "veggie".
define('fruit', 'veggie');
// Теперь обратите внимание на разницу
echo $arr['fruit'], PHP_EOL; // apple
echo $arr[fruit], PHP_EOL; // carrot
// Доступ по ключу без кавычек сработает внутри строки. PHP не ищет константы внутри строк,
// поэтому ошибка здесь не возникнет
echo "Hello $arr[fruit]", PHP_EOL; // Hello apple
// За одним исключением: PHP интерпретирует константы,
// если обращение к массиву внутри строки обернули фигурными скобками
echo "Hello {$arr[fruit]}", PHP_EOL; // Hello carrot
echo "Hello {$arr['fruit']}", PHP_EOL; // Hello apple
// Ещё один способ вывести значение массива — конкатенация
echo "Hello " . $arr['fruit'], PHP_EOL; // Hello apple
]]>
</programlisting>
</example>
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
// Это не сработает и вызовет ошибку разбора наподобие:
// Parse error: parse error, expecting T_STRING' or T_VARIABLE' or T_NUM_STRING'.
// Это относится и к суперглобальным переменным в строках
print "Hello $arr['fruit']";
print "Hello $_GET['foo']";
]]>
</programlisting>
</informalexample>
<para>
Как указывает раздел <link linkend="language.types.array.syntax">о синтаксисе</link>,
внутри квадратных скобок '<literal>[</literal>' и '<literal>]</literal>' требуется указывать выражение. Поэтому следующий код работает:
</para>
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
echo $arr[somefunc($bar)];
]]>
</programlisting>
</informalexample>
<para>
Это пример работы с возвращаемым функцией значением
в качестве индекса массива. PHP также знает о константах:
</para>
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
$error_descriptions[E_ERROR] = "Произошла фатальная ошибка";
$error_descriptions[E_WARNING] = "PHP сообщает о предупреждении";
$error_descriptions[E_NOTICE] = "Это лишь неофициальное замечание";
]]>
</programlisting>
</informalexample>
<para>
Обратите внимание, что <constant>E_ERROR</constant> — это такой же
допустимый идентификатор, как и <literal>bar</literal> в первом примере.
Но последний пример по существу эквивалентен такой записи:
</para>
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
$error_descriptions[1] = "Произошла фатальная ошибка";
$error_descriptions[2] = "PHP выдал предупреждение";
$error_descriptions[8] = "Это просто уведомление";
]]>
</programlisting>
</informalexample>
<para>
поскольку значение константы <constant>E_ERROR</constant> соответствует значению <literal>1</literal> и т. д.
</para>
<sect4 xml:id="language.types.array.foo-bar.why">
<title>Так что же в этом плохого?</title>
<para>
Когда-нибудь в будущем команда разработчиков PHP, возможно, захочет
добавить ещё одну константу или ключевое слово, либо константа из
другого кода может вмешаться.
Например, неправильно использовать
слова <literal>empty</literal> и
<literal>default</literal>, поскольку они относятся к
<link linkend="reserved">зарезервированным ключевым словам</link>.
</para>
<note>
<simpara>
Повторим, внутри строки (<type>string</type>)
в двойных кавычках допустимо не окружать индексы
массива кавычками, поэтому <literal>"$foo[bar]"</literal>
допустимая запись. В примерах выше объяснено, почему,
дополнительная информация дана в разделе
<link linkend="language.types.string.parsing">об обработке
переменных в строках</link>.
</simpara>
</note>
</sect4>
</sect3>
</sect2>
<sect2 xml:id="language.types.array.casting">
<title>Преобразование в массив</title>
<para>
Преобразование целого числа (<type>int</type>), числа с плавающей точкой (<type>float</type>),
строки (<type>string</type>), логического значения (<type>bool</type>) или ресурса (<type>resource</type>)
в массив — создаёт массив
с одним элементом с индексом 0 и значением скаляра, который
был преобразован. Говоря по-другому, выражение <code>(array) $scalarValue</code>
аналогично выражению <literal>array($scalarValue)</literal>.
</para>
<para>
При преобразовании объекта (<type>object</type>) в массив
элементами массива становятся свойства (переменные-члены)
этого объекта. Ключами становятся имена переменных-членов, со следующими примечательными
исключениями: целочисленные свойства становятся недоступными;
к закрытым полям класса (private) в начало дописывается название класса;
к защищённым полям класса (protected) в начало добавляется символ '*'.
Эти добавленные с обоих сторон значения также получат <literal>NUL</literal>-байты.
Неинициализированные <link linkend="language.oop5.properties.typed-properties">типизированные свойства</link>
автоматически отбрасываются.
</para>
<example>
<title>Преобразование в массив</title>
<programlisting role="php">
<![CDATA[
<?php
class A
{
private $B;
protected $C;
public $D;
function __construct()
{
$this->{1} = null;
}
}
var_export((array) new A());
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
array (
'' . "\0" . 'A' . "\0" . 'B' => NULL,
'' . "\0" . '*' . "\0" . 'C' => NULL,
'D' => NULL,
1 => NULL,
)
]]>
</screen>
</example>
<para>
Это может вызвать несколько неожиданное поведение:
</para>
<example>
<title>Приведение объекта к массиву</title>
<programlisting role="php">
<![CDATA[
<?php
class A
{
private $A; // Свойство станет ключом '\0A\0A'
}
class B extends A
{
private $A; // Свойство станет ключом '\0B\0A'
public $AA; // Свойство станет ключом 'AA'
}
var_dump((array) new B());
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
array(3) {
["BA"]=>
NULL
["AA"]=>
NULL
["AA"]=>
NULL
}
]]>
</screen>
</example>
<para>
Приведённый код покажет 2 ключа с названием 'AA', хотя один ключ на самом деле
называется '\0A\0A'.
</para>
<para>
Получится пустой массив,
если преобразовать в массив значение &null;.
</para>
</sect2>
<sect2 xml:id="language.types.array.comparing">
<title>Сравнение</title>
<para>
Массивы сравнивают функцией <function>array_diff</function>
и <link linkend="language.operators.array">операторами массивов</link>.
</para>
</sect2>
<sect2 xml:id="language.types.array.unpacking">
<title>Распаковка массива</title>
<para>
Массив, перед которым указали оператор <code>...</code>, распакуется на месте при определении нового массива.
Распаковка доступна только массивам и объектам, которые реализуют интерфейс
<interfacename>Traversable</interfacename>.
Распаковка массива spread-оператором <code>...</code> доступна с PHP 7.4.0.
</para>
<para>
PHP поддерживает многократное чередование распаковки и стандартных элементов до или после оператора <code>...</code>:
<example>
<title>Простая распаковка массива</title>
<programlisting role="php">
<![CDATA[
<?php
// Применение короткого синтаксиса массива.
// Работает также с синтаксисом array().
$arr1 = [1, 2, 3];
$arr2 = [...$arr1]; // [1, 2, 3]
$arr3 = [0, ...$arr1]; // [0, 1, 2, 3]
$arr4 = [...$arr1, ...$arr2, 111]; // [1, 2, 3, 1, 2, 3, 111]
$arr5 = [...$arr1, ...$arr1]; // [1, 2, 3, 1, 2, 3]
function getArr() {
return ['a', 'b'];
}
$arr6 = [...getArr(), 'c' => 'd']; // ['a', 'b', 'c' => 'd'];
var_dump($arr1, $arr2, $arr3, $arr4, $arr5, $arr6);
]]>
</programlisting>
</example>
</para>
<para>
Распаковка массива оператором <code>...</code> соблюдает семантику функции <function>array_merge</function>,
поэтому более поздние строковые ключи перезаписывают более ранние, а целочисленные ключи перенумеровываются:
<example>
<title>Распаковка массива с дублирующим ключом</title>
<programlisting role="php">
<![CDATA[
<?php
// Строковый ключ
$arr1 = ["a" => 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],
// в котором исходные целочисленные ключи не сохраняются
]]>
</programlisting>
</example>
</para>
<note>
<para>
Ключи, которые не принадлежат ни целочисленному, ни строковому типу,
выбрасывают ошибку <classname>TypeError</classname>.
Такие ключи генерируют только объекты, класс которых реализует интерфейс <interfacename>Traversable</interfacename>.
</para>
</note>
<note>
<para>
До PHP 8.1 распаковка массива со строковым ключом не поддерживалась:
</para>
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
$arr1 = [1, 2, 3];
$arr2 = ['a' => 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]
]]>
</programlisting>
</informalexample>
</note>
</sect2>
<sect2 xml:id="language.types.array.examples">
<title>Примеры</title>
<para>
Массив в PHP — гибкий тип данных. Вот несколько примеров:
</para>
<example>
<title>Видимость массивов</title>
<programlisting role="php">
<![CDATA[
<?php
// Код:
$a = array( 'color' => 'красный',
'taste' => 'сладкий',
'shape' => 'круг',
'name' => 'яблоко',
4 // PHP назначит элементу ключ 0
);
$b = array('a', 'b', 'c');
var_dump($a, $b);
// ...эквивалентен следующему коду:
$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')
var_dump($a, $b);
]]>
</programlisting>
</example>
<example>
<title>Вызов языковой конструкции array()</title>
<programlisting role="php">
<![CDATA[
<?php
// Массив как карта (свойств)
$map = array(
'version' => 4,
'OS' => 'Linux',
'lang' => 'english',
'short_tags' => true
);
var_dump($map);
// Строго числовые ключи,
// что эквивалентно массиву array(0 => 7, 1 => 8, ...)
$array = array(
7,
8,
0,
156,
-10
);
var_dump($array);
$switching = array(
10, // ключ = 0
5 => 6,
3 => 7,
'a' => 4,
11, // ключ = 6 (максимальным числовым индексом было 5)
'8' => 2, // ключ = 8 (число!)
'02' => 77, // ключ = '02'
0 => 12 // значение 10 перезапишется значением 12
);
var_dump($switching);
// пустой массив
$empty = array();
var_dump($empty);
]]>
<!-- TODO example of
- overwriting keys
- using vars/functions as key/values
- warning about references
-->
</programlisting>
</example>
<example xml:id="language.types.array.examples.loop">
<title>Коллекция</title>
<programlisting role="php">
<![CDATA[
<?php
$colors = array('красный', 'голубой', 'зелёный', 'жёлтый');
foreach ($colors as $color) {
echo "Вам нравится $color?\n";
}
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
Вам нравится красный?
Вам нравится голубой?
Вам нравится зелёный?
Вам нравится жёлтый?
]]>
</screen>
</example>
<para>
Непосредственное изменение значений массива
допустимо через передачу значений по ссылке.
</para>
<example xml:id="language.types.array.examples.changeloop">
<title>Изменение элемента в цикле</title>
<programlisting role="php">
<![CDATA[
<?php
$colors = array('red', 'blue', 'green', 'yellow');
foreach ($colors as &$color) {
$color = mb_strtoupper($color);
}
unset($color); /* Переменную удаляют, чтобы очередные записи
в переменной $color не меняли последний элемент массива */
print_r($colors);
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
Array
(
[0] => КРАСНЫЙ
[1] => ГОЛУБОЙ
[2] => ЗЕЛЁНЫЙ
[3] => ЖЁЛТЫЙ
)
]]>
</screen>
</example>
<para>
Следующий пример создаёт массив, индексация которого начинается с единицы.
</para>
<example>
<title>Индексация с единицы</title>
<programlisting role="php">
<![CDATA[
<?php
$firstquarter = array(1 => 'январь', 'февраль', 'март');
print_r($firstquarter);
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
Array
(
[1] => 'январь'
[2] => 'февраль'
[3] => 'март'
)
]]>
</screen>
</example>
<example>
<title>Заполнение массива</title>
<programlisting role="php">
<![CDATA[
<?php
// Заполняем массив элементами из директории
$handle = opendir('.');
while (false !== ($file = readdir($handle))) {
$files[] = $file;
}
closedir($handle);
var_dump($files);
]]>
</programlisting>
</example>
<para>
Массивы упорядочены. Порядок изменяют
разными функциями сортировки. Подробнее об этом рассказано
в разделе «<link linkend="ref.array">Функции для работы с массивами</link>».
Для подсчёта количества элементов в массиве вызывают функцию <function>count</function>.
</para>
<example>
<title>Сортировка массива</title>
<programlisting role="php" annotations="non-interactive">
<![CDATA[
<?php
sort($files);
print_r($files);
]]>
</programlisting>
</example>
<para>
Массивы поддерживают значения в виде других массивов, поскольку массивы принимают произвольные значения.
Поэтому PHP разрешает создавать рекурсивные и многомерные массивы.
</para>
<example>
<title>Рекурсивные и многомерные массивы</title>
<programlisting role="php">
<![CDATA[
<?php
$fruits = array ( "fruits" => array ( "a" => "апельсин",
"b" => "банан",
"c" => "яблоко"
),
"numbers" => array ( 1,
2,
3,
4,
5,
6
),
"holes" => array ( "первая",
5 => "вторая",
"третья"
)
);
var_dump($fruits);
// Ряд примеров доступа к значениям предыдущего массива
echo $fruits["holes"][5]; // Выведет "вторая"
echo $fruits["fruits"]["a"]; // напечатает "апельсин"
unset($fruits["holes"][0]); // удалит "первая"
// Создаст новый многомерный массив
$juices["apple"]["green"] = "хороший";
var_dump($juices);
]]>
</programlisting>
</example>
<para>
Присваивание массива включает копирование значения. Чтобы скопировать массив
по ссылке, указывают <link linkend="language.operators">оператор присваивания по ссылке</link>.
</para>
<example>
<title>Копирование массивов</title>
<programlisting role="php">
<![CDATA[
<?php
$arr1 = array(2, 3);
$arr2 = $arr1;
$arr2[] = 4; // Массив $arr2 изменился,
// Массив $arr1 всё ещё выглядит так: array(2, 3)
$arr3 = &$arr1;
$arr3[] = 4; // Теперь массивы $arr1 и $arr3 одинаковы
var_dump($arr1, $arr2, $arr3);
]]>
</programlisting>
</example>
</sect2>
</sect1>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->