Скачиваний:
18
Добавлен:
02.05.2014
Размер:
906.24 Кб
Скачать

6. Ассоциативные массивы

Возможно, вы уже догадались, что ассоциативные массивы – один из самых мощных инструментов в PHP. Массивы – нечто, что довольно часто реализовывается в интерпретаторах типа PHP (в Perl ассоциативные массивы устроены даже немного хуже, чем в PHP). Давайте рассмотрим чуть подробнее, как с ними работать.

Массивы – это своеобразные контейнеры-переменные для хранения сразу нескольких величин, к которым можно затем быстро и удобно обратиться. Конечно, никто не запрещает вам вообще их не использовать, а, например, давать своеобразные имена переменным, такие как $a1, $a2 и т. д., но представьте, что получится в этом случае, если вам нужно держать в памяти, скажем, тысячу таких переменных. Кроме того, такой способ организации массивов имеет и еще один недостаток – очень трудно перебрать все его значения в цикле, хотя это и возможно:

for($i=0; ; $i++) {

$v="a$i";

if(!isset($$v)) break;

..делаем что-нибудь с $$v

}

Никогда так не делайте! Этот пример приведен здесь лишь для иллюстрации. Если вдруг при написании какого-нибудь сценария вам все-таки мучительно захочется применить этот "трюк", выключите компьютер, подумайте минут 15, а затем снова включите его.

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

Давайте теперь начнем с самого начала. Пусть у нас в программе нужно описать список из нескольких человеческих имен. Можно сделать это так (листинг 6.1):

Листинг 6.1. Инициализация массива

$NamesList[0]="Dmitry";

$NamesList[1]="Helen";

$NamesList[2]="Sergey";

. . .

Таким образом, мы по одному добавляем в массив $NamesList элементы, например, пронумерованные от 0. PHP узнает, что мы хотим создать массив, по квадратным скобкам (нужно заметить, что для этого переменная $NamesList в начале не должна еще быть инициализирована). Я буду в дальнейшем называть массивы, ключи (или, как их часто называют, индексы – то, что стоит в квадратных скобках) которых нумеруются с нуля и идут без пропусков (а это далеко не всегда так, как мы вскоре увидим), списками.

Некоторые стандартные функции PHP, обрабатывающие массивы, требуют передавать в их параметрах именно списки, хотя чаще всего можно это ограничение обойти, передав им любой другой массив. В таком случае они все равно рассматривают массив как обычный список, т. е. не обращают никакого внимания на его ключи. Во многих случаях это бывает нежелательно.

Давайте теперь посмотрим, как можно распечатать наш список. Самый простой способ – воспользоваться циклом for:

echo "А вот первый элемент массива: ".$NamesList[0]."<hr>";

for($i=0; $i<кол-во_элементов; $i++)

echo $NamesList[$i]."<br>";

Количество элементов в массиве легко можно определить, задействуя функцию

count() или ее синоним sizeof():

for($i=0; $i<count($NamesList); $i++)

echo $NamesList[$i]."<br>";

Создание массива "на лету". Автомассивы

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

$NamesList[]="Dmitry";

$NamesList[]="Helen";

$NamesList[]="Sergey";

В этом случае PHP сам начнет (конечно, если переменная $NamesList еще не существует) нумерацию с нуля и каждый раз будет прибавлять к счетчику по единичке, создавая список. Согласитесь, довольно удобно. Разумеется, можно использовать [] и не только в таком простом контексте, очень часто они применяются для более общего действия – добавления элемента в конец массива, например:

Unset($FNames); // на всякий случай стираем массив

while($f=очередное_имя_файла_в_текущем каталоге)

if(расширение_$f_есть_txt) $FNames[]=$f;

// теперь $FNames содержит список файлов с расширением txt

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

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

$Names["Koteroff"] = "Dmitry";

$Names["Ivanov"] = "Ivan";

$Names["Petrov"] = "Peter";

Далее, мы можем распечатать имя любого абонента командой:

echo $Names["Ivanov"];

$f="Koteroff";

echo $Names[$f];

Как видите, тут никаких особенностей нет, все работает совершенно аналогично спискам, только с нецифровыми ключами. Возможно, вы скажете, что это не совсем так: например, нельзя воспользоваться циклом for, как мы это делали раньше, для вывода всех персоналий, и окажетесь правы. Вскоре мы рассмотрим целых три приема, с помощью которых можно перебрать все элементы массива. Вы, скорее всего, будете применять их даже и для списков – настолько они удобны и универсальны, а к тому же и работают быстрее, чем последовательный перебор в цикле for с использованием $i.

Инструкция list()

Пусть у нас есть некоторый массив-список $List с тремя элементами: имя человека, его фамилия и возраст. Нам бы хотелось присвоить переменным $name, $surname и $age эти величины. Это, конечно, можно сделать так:

$name=$List[0];

$surname=$List[1];

$age=$List[2];

Но гораздо изящнее будет воспользоваться инструкцией list(), предназначенной как раз для таких целей:

list($name,$surname,$age)=$List;

Согласитесь, выглядит несколько приятнее. Конечно, list() можно задействовать для любого количества переменных: если в массиве не хватит элементов, чтобы их заполнить, им просто присвоятся неопределенные значения. Что, если нам нужны только второй и третий элемент массива $List? В этом случае имеет смысл пропустить первый параметр в инструкции list(), вот так:

list(,$surname,$age)=$List;

Таким образом, мы получаем в $surname и $age фамилию и возраст человека, не обращая внимания на его имя в первом аргументе. Разумеется, можно пропускать любое число элементов, как слева или справа, так и посередине списка. Главное – не забыть проставить нужное количество запятых.

Списки и ассоциативные массивы: путаница?..

Следует сказать несколько слов насчет ассоциативных массивов языка PHP. Во-первых, на самом деле все "остальные" массивы также являются ассоциативными (в частности, списки – тоже). Во-вторых, ассоциативные массивы в PHP являются направленными, т. е. в них существует определенный (и предсказуемый) порядок элементов, не зависящий от реализации. А значит, есть первый и последний элементы, и для каждого элемента можно определить следующий за ним. Именно по этой причине мне не нравится название "хэш" (в буквальном переводе – "мешанина"), хотя, конечно, в реализации PHP наверняка используются алгоритмы хэширования для увеличения быстродействия. Операция [] всегда добавляет элемент в конец массива, присваивая ему при этом такой числовой индекс, который бы не конфликтовал с уже имеющимися в массиве (точнее, выбирается номер, превосходящий все имеющиеся цифровые ключи в массиве). Вообще говоря, любая операция $Array[ключ_]=значение всегда добавляет элемент в конец массива, конечно, за исключением тех случаев, когда ключ уже присутствует в массиве. Если вы захотите изменить порядок следования элементов в ассоциативном массиве, не изменяя в то же время их ключей, это можно сделать одним из двух способов: воспользоваться функциями сортировки, либо же создать новый пустой массив и заполнить его в нужном порядке, пройдясь по элементам исходного массива.

Инструкция array() и многомерные массивы

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

$Names["Ivanov"] ="Dmitry";

$Names["Petrova"]="Helen";

Теперь можно, как мы знаем, написать:

echo $Names["Petrova"]; // выведет Helen

echo $Names["Oshibkov"]; // ошибка: в массиве нет такого элемента!

Идем дальше. Прежде всего обратим внимание: приведенным выше механизмом мы никак не смогли бы создать пустой массив. Однако он очень часто может нам понадобиться, например, если мы не знаем, что раньше было в массиве $Names, но хотим его проинициализировать указанным путем. Кроме того, каждый раз задавать массив указанным выше образом не очень-то удобно – приходится все время однообразно повторять строку $Names...

Так вот, существует и второй способ создания массивов, выглядящий значительно компактнее. Это использование оператора array(). Например:

// создает пустой массив $Names

$Names=array();

// создает такой же массив, как в предыдущем примере с именами

$Names=array("Ivanov"=>"Dmitry", "Petrova"=>"Helen");

// создает список с именами (нумерация 0,1,2)

$NamesList=array("Dmitry","Helen","Sergey");

Теперь займемся вопросом, как формировать двумерные (и вообще многомерные) массивы. Это довольно просто. В самом деле, я уже говорил, что значениями переменных (и значениями элементов массива тоже, поскольку PHP не делает никаких различий между переменными и элементами массива) может быть все, что угодно, в частности – опять же массив. Так, можно создавать ассоциативные массивы (а можно – списки) с любым числом измерений. Например, если кроме имени о человеке известен также его возраст, то можно инициировать массив $Names так:

$Names["Ivanov"] = array("name"=>"Dmitry","age"=>25);

$Names["Petrova"] = array("name"=>"Helen", "age"=>23);

или даже так:

$Names=array(

"Ivanov" => array("name"=>"Dmitry","age"=>25),

"Petrova"=> array("name"=>"Helen", "age"=>23)

);

Как же добраться до нужного нам элемента в нашем массиве? Нетрудно догадаться по аналогии с другими языками:

echo $Names["Ivanov"]["age"]; // напечатает "25"

echo $Names["Petrova"]["bad"]; // ошибка: нет такого элемента "bad"

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