Массивы

На самом деле массив в PHP - это упорядоченное отображение, которое устанавливает соответствие между значением и ключем. Этот тип оптимизирован в нескольких направлениях, поэтому вы можете использовать его как собственно массив, список (вектор), хэш-таблицу (являющуюся реализацией карты), словарь, коллекцию, стэк, очередь или, возможно, как что-то еще. Поскольку вы можете иметь в качестве значения другой массив PHP, вы можете также легко эмулировать деревья.

Объяснение этих структур данных выходит за рамки данного справочного руководства, но вы найдете как минимум один пример каждой из них. За дополнительной информацией вы можете обратиться к соответствующей литературе по этой обширной теме.

Синтаксис

Определение при помощи array()

Массив может быть создан языковой конструкцией array(). В качестве параметров она принимает определенное количество разделенных запятыми пар key => value (ключ => значение).

array( [key =>] value
     , ...
     )
// key может быть integer или string
// value может быть любым значением

<?php
$arr
= array("foo" => "bar", 12 => true);

echo
$arr["foo"]; // bar
echo $arr[12];    // 1
?>

key может быть либо integer, либо string. Если ключ - это стандартное представление integer, он так и будет интерпретироваться (т.е. "8" будет восприниматься как 8, тогда как "08" будет интерпретироваться как "08"). В PHP нет разницы между индексными и ассоциативными массивами; существует только один тип массива, который может содержать и числовые, и строковые индексы.

Значение может быть любого имеющегося в PHP типа.

<?php
$arr
= array("somearray" => array(6 => 5, 13 => 9, "a" => 42));

echo
$arr["somearray"][6];    // 5
echo $arr["somearray"][13];   // 9
echo $arr["somearray"]["a"];  // 42
?>

Если вы не указываете ключ для приведенного значения, то берется максимальный числовой индекс и новый ключ будет равен этому максимуму + 1. Если вы укажите ключ, которому уже присвоено значение, оно будет перезаписано.

<?php
// Этот массив эквивалентен ...
array(5 => 43, 32, 56, "b" => 12);

// ...этому массиву
array(5 => 43, 6 => 32, 7 => 56, "b" => 12);
?>

Внимание

Начиная с PHP 4.3.0, вышеописанное поведение генерации индекса изменено. Теперь, если вы будете использовать массив, в котором максимальным в настоящий момент является отрицательный ключ, то следующий созданный ключ будет нулевым (0). Раньше новым индексом становился самый большой существующий ключ + 1, так же как и у положительных индексов.

Используя в качестве ключа TRUE вы получите ключ 1 типа integer. Используя в качестве ключа FALSE вы получите ключ 0 типа integer. Используя в качестве ключа NULL, вы получите пустую строку. Использование в качестве ключа пустой строки создаст (или перезапишет) ключ с пустой строкой и его значение; это не то же самое, что использование пустых квадратных скобок.

Вы не можете использовать в качестве ключей массивы или объекты. Это вызовет предупреждение: Illegal offset type ('Недопустимый тип смещения').

Создание/модификация с помощью синтаксиса квадратных скобок

Также вы можете изменять существующий массив, явно устанавливая значения в нем.

Это выполняется присвоением значений массиву при указании в скобках ключа. Кроме того, вы можете опустить ключ, в этом случае добавьте к имени переменной пустую пару скобок ("[]").
$arr[key] = value;
$arr[] = value;
// key может быть integer или string
// value может быть любым значением
Если массив $arr еще не существует, он будет создан. Таким образом, это еще один способ определить массив. Для изменения определенного значения просто присвойте элементу с его ключом новое значение. Если вы хотите удалить пару ключ/значение, вам нужно использовать функцию unset().

<?php
$arr
= array(5 => 1, 12 => 2);

$arr[] = 56;    // В этом месте скрипта это
                // эквивалентно $arr[13] = 56;

$arr["x"] = 42; // Это добавляет к массиву новый
                // элемент с ключом "x"
                
unset($arr[5]); // Это удаляет элемент из массива

unset($arr);    // Это удаляет массив полностью
?>

Замечание: Как уже говорилось выше, если вы не укажите в скобках ключа, то будет взят максимальный из существующих целочисленных индексов, и новым ключом будет это максимальное значение + 1. Если целочисленных индексов еще нет, то ключом будет 0 (ноль). Если вы укажите ключ, которому уже присвоено значение, оно будет перезаписано.

Внимание

Начиная с PHP 4.3.0, вышеописанное поведение генерации индекса изменено. Теперь, если вы будете использовать массив, в котором максимальным в настоящий момент является отрицательный ключ, то следующий созданный ключ будет нулевым (0). Раньше новым индексом становился самый большой существующий ключ + 1, так же как и у положительных индексов.

Обратите внимание, что максимальный числовой ключ, используемый для этого не обязательно должен существовать в массиве в настоящий момент. Он просто должен был существовать с момента последнего переиндексирования массива. Это иллюстрирует следующий пример:

<?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);
?>

Вышеприведенный пример выведет следующее:
Array
(
    [0] => 1
    [1] => 2
    [2] => 3
    [3] => 4
    [4] => 5
)
Array
(
)
Array
(
    [5] => 6
)
Array
(
    [0] => 6
    [1] => 7
)

Полезные функции

Для работы с массивами существует достаточное количество полезных функций. Смотрите раздел функции для работы с массивами.

Замечание: Функция unset() позволяет удалять ключи массива. Обратите внимание, что массив НЕ будет переиндексирован. Если вы использовали только "обычные числовые индексы" (увеличивающиеся на единицу, начиная с нуля), вы можете переиндексировать массив используя array_values().

<?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 =>'три')
?>

Управляющая конструкция foreach существует специально для массивов. Она предоставляет возможность легко пройтись по массиву.

Массив делает и не делает

Почему $foo[bar] это неверно?

Вы всегда должны заключать индекс ассоциативного массива в кавычки. К примеру, пишите $foo['bar'], а не $foo[bar]. Но почему $foo[bar] это неверно? Возможно, вы встречали в старых скриптах следующий синтаксис:

<?php
$foo
[bar] = 'враг';
echo
$foo[bar];
// и т. д.
?>

Это неверно, хотя и работает. Тогда почему же это неверно? Причина в том, что этот код содержит неопределенную константу (bar), а не строку ('bar' - обратите внимание на кавычки), и PHP в будущем может определить константу, которая к несчастью для вашего кода будет иметь то же самое имя. Это работает, потому что PHP автоматически преобразует голую строку (не заключенную в кавычки строку, которая не соответствует ни одному из известных символов) в строку, которая содержит голую строку. Например, если константа с именем bar не определена, то PHP заменит bar на строку 'bar' и использует ее.

Замечание: Это не означает, что нужно всегда заключать ключ в кавычки. Нет необходимости заключать в кавычки константы или переменные, поскольку это помешает PHP обрабатывать их.

<?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";
}
?>

Замечание: Вышеприведенный код выведет следующее:
Проверяем 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

Дополнительные примеры, демонстрирующие этот факт:

<?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
?>

Когда вы переведете error_reporting() в режим отображения ошибок уровня E_NOTICE (такой как E_ALL), вы увидите эти ошибки. По умолчанию error_reporting установлена их не отображать.

Как указано в разделе синтаксис, внутри квадратных скобок ('[' и ']') должно быть выражение. Это означает, что вы можете писать подобно этому:

<?php
echo $arr[somefunc($bar)];
?>

Это пример использования возвращаемого функцией значения в качестве индекса массива. PHP известны также и константы, как вы, возможно, видели упоминание E_* раньше.

<?php
$error_descriptions
[E_ERROR]   = "Произошла фатальная ошибка";
$error_descriptions[E_WARNING] = "PHP сообщает предупреждение";
$error_descriptions[E_NOTICE]  = "Это лишь неофициальное замечание";
?>

Обратите внимание, что E_ERROR - это такой же верный идентификатор, как и bar в первом примере. Но последний пример по сути эквивалентен такой записи:

<?php
$error_descriptions
[1] = "Произошла фатальная ошибка";
$error_descriptions[2] = "PHP сообщает предупреждение";
$error_descriptions[8] = "Это лишь неофициальное замечание";
?>

поскольку E_ERROR соответствует 1 и т. д.

Как мы уже объяснили в вышеприведенных примерах, $foo[bar] по-прежнему работает, но это неверно. Это работает, поскольку в соответствии со своим синтаксисом bar ожидается как константа. Однако, в данном случае константы с именем bar не существует. В таком случае PHP предполагает, что, написав bar, вы имели ввиду строку "bar", но забыли указать кавычки.

Так что же в этом плохого?

Когда-нибудь в будущем команда разработчиков PHP возможно пожелает добавить еще одну константу или ключевое слово, либо вы можете ввести в ваше приложение еще одну константу и тогда у вас могут возникнуть проблемы. Например, вы уже не можете использовать таким образом слова empty и default, поскольку они являются зарезервированными ключевыми словами.

Замечание: Повторим, внутри строки (string), заключенной в двойные кавычки правильным является не окружать индексы массива кавычками, поэтому "$foo[bar]" является верным. Более подробно почему - смотрите вышеприведенные примеры, а также раздел обработка переменных в строках.

Преобразование в массив

Для любого из типов: integer, float, string, boolean и resource, если вы преобразуете значение в массив, вы получите массив с одним элементом (с индексом 0), являющимся скалярным значением, с которого вы начали.

Если вы преобразуете в массив объект (object), вы получите в качестве элементов массива свойства (переменные-члены) этого объекта. Ключами будут имена переменных-членов.

Если вы преобразуете в массив значение NULL, вы получите пустой массив.

Сравнение

Массивы можно сравнивать при помощи функции array_diff() и Операторов массивов.

Примеры

Тип массив в PHP является очень гибким, поэтому мы приведем здесь несколько примеров, чтобы продемонстрировать вам все возможности массивов.

<?php
// это
$a = array( 'color' => 'red',
            
'taste' => 'sweet',
            
'shape' => 'round',
            
'name'  => 'apple',
                       
4        // ключом будет 0
          
);

// полностью соответствует
$a['color'] = 'red';
$a['taste'] = 'sweet';
$a['shape'] = 'round';
$a['name']  = 'apple';
$a[]        = 4;        // ключом будет 0

$b[] = 'a';
$b[] = 'b';
$b[] = 'c';
// создаст массив array(0 => 'a' , 1 => 'b' , 2 => 'c'),
// или просто array('a', 'b', 'c')
?>

Пример 11-4. Использование array()

<?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();
?>

Пример 11-5. Коллекция

<?php
$colors
= array('красный', 'синий', 'зеленый', 'желтый');

foreach (
$colors as $color) {
    echo
"Вам нравится $color?\n";
}
?>

Результат работы приведенного скрипта будет следующий:

Вам нравится красный?
Вам нравится синий?
Вам нравится зеленый?
Вам нравится желтый?

Обратите внимание, что в настоящее время невозможно изменять значения массива в таком цикле напрямую. Однако можно сделать так:

Пример 11-6. Коллекция

<?php
foreach ($colors as $key => $color) {
    
// не будет работать:
    //$color = strtoupper($color);
    
    // работает:
    
$colors[$key] = strtoupper($color);
}
print_r($colors);

?>

Результат работы приведенного скрипта будет следующий:

Array
(
    [0] => КРАСНЫЙ
    [1] => СИНИЙ
    [2] => ЗЕЛЕНЫЙ
    [3] => ЖЕЛТЫЙ
)

Следующий пример создает начинающийся с единицы массив.

Пример 11-7. Индекс, начинающийся с единицы

<?php
$firstquarter  
= array(1 => 'Январь', 'Февраль', 'Март');
print_r($firstquarter);

?>

Результат работы приведенного скрипта будет следующий:

Array 
(
    [1] => 'Январь'
    [2] => 'Февраль'
    [3] => 'Март'
)

Пример 11-8. Заполнение массива

<?php
// заполняет массив всеми элементами директории
$handle = opendir('.');
while (
false !== ($file = readdir($handle))) {
    
$files[] = $file;
}
closedir($handle);
?>

Массивы упорядочены. Вы можете изменять порядок элементов, используя различные функции сортировки. Для дополнительной информации смотрите раздел функции для работы с массивами. Вы можете подсчитать количество элементов в массиве, используя функцию count().

Пример 11-9. Сортировка массива

<?php
sort
($files);
print_r($files);
?>

Поскольку значение массива может быть чем угодно, им также может быть другой массив. Таким образом вы можете создавать рекурсивные и многомерные массивы.

Пример 11-10. Рекурсивные и многомерные массивы

<?php
$fruits
= array ( "фрукты" => array ( "a" => "апельсин",
                                      
"b" => "банан",
                                      
"c" => "яблоко"
                                    
),
                  
"числа"  => array ( 1,
                                      
2,
                                      
3,
                                      
4,
                                      
5,
                                      
6
                                    
),
                  
"дырки"  => array (      "первая",
                                      
5 => "вторая",
                                           
"третья"
                                    
)
                );

// Несколько примеров доступа к значениям предыдущего массива
echo $fruits["дырки"][5];    // напечатает "вторая"
echo $fruits["фрукты"]["a"]; // напечатает "апельсин"
unset($fruits["дырки"][0]);  // удалит "первая"

// Создаст новый многомерный массив
$juices["яблоко"]["зеленое"] = "хорошее";
?>

Обратите внимание, что при присваивании массива всегда происходит копирование значения. Чтобы копировать массив по ссылке, вам нужно использовать оператор ссылки.

<?php
$arr1
= array(2, 3);
$arr2 = $arr1;
$arr2[] = 4; // $arr2 изменился,
             // $arr1 по прежнему array(2,3)
             
$arr3 = &$arr1;
$arr3[] = 4; // теперь $arr1 и $arr3 эквивалентны
?>