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

1532 lines
51 KiB
XML
Raw 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: c97d8be813dd0189f2a97359795fbe7173792878 Maintainer: shein Status: ready -->
<!-- Reviewed: no -->
<sect1 xml:id="language.types.array">
<title>Массивы</title>
<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>
Существует короткий синтаксис массива, который заменяет
языковую конструкцию <literal>array()</literal> выражение <literal>[]</literal>.
</para>
</note>
<example>
<title>Простой массив</title>
<programlisting role="php">
<![CDATA[
<?php
$array = array(
"foo" => "bar",
"bar" => "foo",
);
// Работа с коротким синтаксисом массива
$array = [
"foo" => "bar",
"bar" => "foo",
];
?>
]]>
</programlisting>
</example>
<para>
Ключ массива (<replaceable>key</replaceable>) разрешено указывать либо как целочисленное значение (<type>int</type>),
либо как строку (<type>string</type>).
Значение массива (<replaceable>value</replaceable>) может принадлежать любому типу данных.
</para>
<para xml:id="language.types.array.key-casts">
Дополнительно произойдут следующие преобразования ключа <replaceable>key</replaceable>:
<itemizedlist>
<listitem>
<simpara>
Строки (<type>string</type>), содержащие целое число (<type>int</type>)
(исключая случаи, когда перед числом указывают знак <literal>+</literal>),
будут преобразованы в целое число (<type>int</type>).
Например, ключ со значением <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>
Если нескольким элементам в объявлении массива указан одинаковый ключ, то только
последний будет сохранён, а другие будут перезаписаны.
</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>key</replaceable>) — необязателен. Если он не указан,
PHP инкрементирует предыдущее наибольшее целочисленное (<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>
<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>
<para>
Этот пример включает все вариации преобразования ключей и перезаписи элементов
</para>
</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];
?>
]]>
</programlisting>
</example>
<note>
<para>
Попытка доступа к неопределённому ключу в массиве — это то же самое,
что и попытка доступа к любой другой неопределённой переменной:
будет выдана ошибка уровня <constant>E_WARNING</constant>
(ошибка уровня <constant>E_NOTICE</constant> до PHP 8.0.0),
и результат будет равен &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>
Если массив <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>
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
$arr = array(5 => 1, 12 => 2);
$arr[] = 56; // В этом месте скрипта это
// то же самое, что и $arr[13] = 56;
$arr["x"] = 42; // Это добавляет в массив новый
// элемент с ключом «x»
unset($arr[5]); // Это удаляет элемент из массива
unset($arr); // Это удаляет весь массив
?>
]]>
</programlisting>
</informalexample>
<note>
<para>
Как было сказано ранее, если разработчик не указал ключ, то будет взят максимальный
из существующих целочисленных (<type>int</type>) индексов, и новым ключом будет
это максимальное значение (в крайнем случае 0) плюс 1. Если целочисленных (<type>int</type>) индексов
ещё нет, то ключом будет <literal>0</literal> (ноль).
</para>
<para>
Учитывают, что максимальное целое значение ключа <emphasis>не обязательно
существует в массиве в текущий момент</emphasis>. Оно могло существовать
в массиве какое-то время с момента последней переиндексации.
Следующий пример это иллюстрирует:
</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>
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
$source_array = ['foo', 'bar', 'baz'];
[$foo, $bar, $baz] = $source_array;
echo $foo; // выведет «foo»
echo $bar; // выведет «bar»
echo $baz; // выведет «baz»
?>
]]>
</programlisting>
</informalexample>
<para>
Деструктуризацию массива также выполняют в конструкции &foreach;
для деструктуризации многомерного массива во время итерации по массиву.
</para>
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
$source_array = [
[1, 'John'],
[2, 'Jane'],
];
foreach ($source_array as [$id, $name]) {
// логика работы с $id и $name
}
?>
]]>
</programlisting>
</informalexample>
<para>
Элементы массива будут проигнорированы, если переменная не указана.
Деструктуризация массива начинается с индекса <literal>0</literal>.
</para>
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
$source_array = ['foo', 'bar', 'baz'];
// Присваивание элемента с индексом 2 переменной $baz
[, , $baz] = $source_array;
echo $baz; // выведет "baz"
?>
]]>
</programlisting>
</informalexample>
<para>
С PHP 7.1.0 ассоциативные массивы также разрешено деструктурировать.
Это упрощает выбор нужного элемента в массивах с числовым индексом,
так как индекс может быть указан явно.
</para>
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
$source_array = ['foo' => 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»
?>
]]>
</programlisting>
</informalexample>
<para>
Деструктуризацией массив пользуются, чтобы поменять две переменные местами.
</para>
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
$a = 1;
$b = 2;
[$b, $a] = [$a, $b];
echo $a; // выведет 2
echo $b; // выведет 1
?>
]]>
</programlisting>
</informalexample>
<note>
<para>
Оператор <literal>...</literal> не поддерживается в присваиваниях.
</para>
</note>
<note>
<para>
Попытка получить доступ к неопределённому ключу массива
аналогична обращению к любой другой неопределённой переменной:
будет выдано сообщение об ошибке уровня <constant>E_WARNING</constant>
(ошибки уровня <constant>E_NOTICE</constant> до PHP 8.0.0),
а результатом будет значение &null;.
</para>
</note>
</sect3>
</sect2>
<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>
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
$a = array(1 => 'один', 2 => 'два', 3 => 'три');
unset($a[2]);
/* даст массив, представленный так:
$a = array(1 => 'один', 3 => 'три');
а НЕ так:
$a = array(1 => 'один', 2 => 'три');
*/
$b = array_values($a);
// Теперь $b это array(0 => 'один', 1 => 'три')
?>
]]>
</programlisting>
</informalexample>
</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> — обратите внимание
на кавычки). Это работает, потому что PHP автоматически преобразовывает
<emphasis>«голую строку»</emphasis> (не заключённую в кавычки строку,
которая не соответствует ни одному из известных символов языка) в строку
со значением этой «голой строки». Например, если константа с именем <constant>bar</constant>
не определена, то PHP заменит bar на
строку <literal>«bar»</literal> и будет работать с ней.
</para>
<warning>
<simpara>
Резервный вариант для обработки неопределённой константы как пустой строки
выдаёт ошибку уровня <constant>E_NOTICE</constant>.
Начиная с PHP 7.2.0 поведение объявлено устаревшим
и выдаёт ошибку уровня <constant>E_WARNING</constant>.
Начиная с PHP 8.0.0 удалено и выбрасывает исключение <classname>Error</classname>.
</simpara>
</warning>
<note>
<simpara>
Это не значит, что нужно <emphasis>всегда</emphasis> заключать
ключ в кавычки. Не обязательно заключать в кавычки <link
linkend="language.constants">константы</link> или <link
linkend="language.variables">переменные</link>, поскольку это
помешает PHP обрабатывать их.
</simpara>
<informalexample>
<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>
</informalexample>
&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>
</note>
<para>
Дополнительные примеры, которые подтверждают этот факт:
</para>
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
// Показываем все ошибки
error_reporting(E_ALL);
$arr = array('fruit' => '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
?>
]]>
</programlisting>
</informalexample>
<para>
Если директива <link linkend="ini.error-reporting">error_reporting</link> настроена
на режим отображения ошибок уровня
<constant>E_NOTICE</constant> (например,
<constant>E_ALL</constant>), ошибки сразу будут видны.
По умолчанию директива <link linkend="ini.error-reporting">
error_reporting</link> настроена на то, чтобы не показывать предупреждения.
</para>
<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 и значением скаляра, который
был преобразован. Говоря по-другому, выражение <literal>(array) $scalarValue</literal>
аналогично выражению <literal>array($scalarValue)</literal>.
</para>
<para>
Если объект (<type>object</type>) будет преобразован в массив,
элементами массива будут свойства (переменные-члены)
этого объекта. Ключами будут имена переменных-членов, со следующими примечательными
исключениями: целочисленные свойства станут недоступны;
к закрытым полям класса (private) в начало будет дописано имя класса;
к защищённым полям класса (protected) в начало будет добавлен символ '*'.
Эти добавленные с обоих сторон значения также получат <literal>NUL</literal>-байты.
Неинициализированные <link linkend="language.oop5.properties.typed-properties">типизированные свойства</link>
автоматически отбрасываются.
</para>
<informalexample>
<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>
</informalexample>
<para>
Это может вызвать несколько неожиданное поведение:
</para>
<informalexample>
<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>
</informalexample>
<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>, разрешено распаковывать.
Распаковка массива оператором <code>...</code> доступна начиная с PHP 7.4.0.
</para>
<para>
Массив разрешено распаковывать несколько раз и добавлять обычные элементы до или после оператора <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']
?>
]]>
</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>
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
// Этот код:
$a = array( 'color' => 'красный',
'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').
?>
]]>
</programlisting>
</informalexample>
<example>
<title>Вызов языковой конструкции array()</title>
<programlisting role="php">
<![CDATA[
<?php
// Массив как карта (свойств)
$map = array(
'version' => 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();
?>
]]>
<!-- 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
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);
?>
]]>
</programlisting>
</example>
<para>
Массивы упорядочены. Порядок изменяют
разными функциями сортировки. Подробнее об этом рассказано
в разделе «<link linkend="ref.array">Функции
для работы с массивами</link>». Для подсчёта количества элементов
в массиве вызывают функцию <function>count</function>.
</para>
<example>
<title>Сортировка массива</title>
<programlisting role="php">
<![CDATA[
<?php
sort($files);
print_r($files);
?>
]]>
</programlisting>
</example>
<para>
Поскольку значению массива разрешено быть любым,
значение может быть также другим массивом. Поэтому разрешено создавать
рекурсивные и многомерные массивы.
</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 => "вторая",
"третья"
)
);
// Несколько примеров доступа к значениям предыдущего массива
echo $fruits["holes"][5]; // напечатает «вторая»
echo $fruits["fruits"]["a"]; // напечатает «апельсин»
unset($fruits["holes"][0]); // удалит «первая»
// Создаст новый многомерный массив
$juices["apple"]["green"] = "хороший";
?>
]]>
</programlisting>
</example>
<para>
Присваивание массива включает копирование значения. Чтобы скопировать массив
по ссылке, указывают <link linkend="language.operators">оператор присваивания по ссылке</link>.
</para>
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
$arr1 = array(2, 3);
$arr2 = $arr1;
$arr2[] = 4; // Массив $arr2 изменился,
// Массив $arr1 всё ещё выглядит так: array(2, 3)
$arr3 = &$arr1;
$arr3[] = 4; // Теперь массивы $arr1 и $arr3 одинаковы
?>
]]>
</programlisting>
</informalexample>
</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
-->