Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лаб №5. Конструкции. Массивы. (Продолжение)!!!....doc
Скачиваний:
10
Добавлен:
22.04.2019
Размер:
643.07 Кб
Скачать

Многомерные массивы

Это массив, который содержит массив внутри ячейки массива.

Пример

<?php

$auto["bmw"]=array("color"=>"белый", "year"=>"2005", "probeg"=>"2000");

$auto["audi"]=array("color"=>"синий", "year"=>"2003", "probeg"=>"2300");

Echo "<br> Год bmw - ".$auto["bmw"]["year"];

Echo "<br> Год audi - ".$auto["audi"]["year"];

?>

или

<?

$auto["bmw"]=array("color"=>"белый","year"=>"2005", "probeg"=>"2000");

$auto["audi"]=array("color"=>"синий", "year"=>"2003", "probeg"=>"2300");

Echo "<br> Год bmw - ".$auto["bmw"]["year"].".Цвет -".$auto["bmw"]["color"].".Пробег -".$auto["bmw"]["probeg"];

Echo "<br> Год audi - ".$auto["audi"]["year"];

?>

Инструкция list

Пример

$box=array ("Персик","Огурец");

List($fruit,$vegetable)=$box;

Echo"<br>$fruit<br>$vegetable";

Пусть у нас есть некоторый массив-список $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 и $аgе фамилию и возраст человека, не обращая внимания на его имя в первом аргументе.

Замечание

Разумеется, можно пропускать любое число элементов, как слева или справа, так и посередине списка. Главное — не забыть проставить нужное количество запятых.

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

Функция isset и функция unset

Функция isset определяет существует ли переменная.

$z=isset($f) – если переменная $f существует то функция возвращает 1.

Используется совместно с инструкцией if.

If(isset($c)== "1")

{

Echo "переменная с существует и её значение : $c";

}

Else

{

Echo "переменная с не существует ";

{

функция unset – стирает переменную

пример

$v=10;

Unset($v);

echo "$v ";

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

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

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

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

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

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

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

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

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

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

$Names=array();

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

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

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

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

Формирование двумерных (и вообще многомерных) массивов. В самом деле, значениями переменных (и значениями элементов массива тоже, поскольку РНР не делает никаких различий между переменными и элементами массива) может быть все, что угодно, в частности — опять же массив. Так, можно создавать ассоциативные массивы (а можно — списки) с любым числом измерений. Например, если кроме имени о человеке известен также его возраст, то можно инициировать массив $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"

Можно видеть, что ассоциативные массивы в РНР удобно использовать как некие структуры, хранящие данные. Это единственный возможный способ организации структур, но он довольно гибок.

Операции над массивами

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

Доступ по ключу

Ассоциативные массивы — объекты, которые наиболее приспособлены для выборки из них данных путем указания нужного ключа. В РНР и для всех массивов, и для списков (которые, также являются массивами) используется один и тот же синтаксис, что является очень большим достоинством. Вот как это выглядит:

echo $Arr["anykey"]; // выводит элемент массива $Агг с ключом anykey

echo $Arr["first"]["second"]; // так используются двумерные массивы

echo (SomeFuncThatReturnsArrayO)[5];

// ОШИБКА! Так нельзя! А правильно будет:

$Arr= SomeFuncThatReturnsArray();

echo $Arr[5];

Последний пример показывает, что РНР сильно отличается от Си с точки зрения работы с массивами: в нем нет такого понятия, как "контекст массива", а значит, мы не можем применить [ ] непосредственно к значению, возвращенному функцией.

Величина $ Arr [КЛЮЧ] является полноценным "левым значением", т. е. может стоять в левой части оператора присваивания, от нее можно брать ссылку с помощью оператора &, и т. д. Например:

$Arr["anykey"]=array(100,200); // присваиваем элементу массива 100

$ref=&$Arr["first"]["second"]; // $ref — синоним элемента массива

$Arr[]="for add"; // добавляем новый элемент

Функция count()

Мы можем определить размер (число элементов) в массиве при помощи

стандартной функции count ():

$num=count($Names); // теперь в $num — число элементов в массиве

Отметим, что count ( ) работает не только с массивами, но и с объектами и даже с обычными переменными (для последних count () всегда равен 1, как будто переменная — это массив с одним элементом).

Пример.

$name[]="Александр";

$name[]="Иван";

$name[]="Аслан";

$h2=count($name);

Echo"<br> В массиве name найдено-$h2 элемента."

Слияние массивов

Еще одна фундаментальная операция — слияние массивов, т. е. создание массива, содержащего как элементы одного, так и другого массива. Реализуется это при помощи оператора +. Например:

$a=array("a"=>"aa", "b"=>"bb");

$b=array("c"=>"cc", "d"=>"dd");

$c=$a+$b;

В результате в $с окажется ассоциативный массив, содержащий все 4 элемента, а именно: array("a"=>"aa", "b"=>"bb", "c"=>"cc", "d"=>"dd"), причем именно в указанном порядке. Если бы мы написали $с=$b+$а, результат бы был немного другой, а именно: array ("c"=>"cc", "d"=>"dd", ;'а"=>"аа", "b"=>"bb"), т.е. элементы расположены в другом порядке.

То есть проявляется направленность массивов. Она заставляет оператор + стать некоммутативным, т. е. $а+$b не равно $b+$а, если $а и $b - массивы.

Следует быть особенно внимательным при слиянии таким образом списков.

Рассмотрим следующие операторы:

$а=аггау(10,20,30);

$b=array(100,200);

$с=$а+$b;

Вместо, $с будет аггау(10,20,30,100,200) на которое можно было бы рассчитывать, там окажется array(10,20,30). И вот почему так происходит. При конкатенации массивов с некоторыми одинаковыми элементами (то есть, элементами с одинаковыми ключами) в результирующем массиве останется только один элемент с таким же ключом — тот, который был в первом массиве, и на том же самом месте. Последний факт может слегка озадачить. Казалось бы, элементы массива $b по логике должны заменить элементы из $а. Однако все происходит наоборот. И еще следующий пример:

$а=аггау('а'=>10, 'Ь'=>20);

$b=array('Ь'=>'new? ' ) ;

$a+=$b;

Ожидается, что оператор += обновит элементы $а при помощи элементов $b. Но в результате этих операций значение $а не изменится*. Как же все-таки обновить элементы в массиве $а? Получается, только прямым способом — с помощью цикла (на самом деле, в РНР4 добавлена специальная функция array_merge (), лишенная указанного недостатка):

foreach ($b as $k=>$v) $a[$k]=$v;

Еще об операциях слияния массивов. Цепочка

$z=$a+$b+$c+...и т. д.;

эквивалентна

$z=$a; $z+=$b; $z+=$c; . . .и т. д.

Оператор += для массивов делает примерно то же, что и оператор += для чисел, а именно — добавляет в свой левый операнд элементы, перечисленные в правом операнде-массиве, если они еще не содержатся в массиве слева.

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

Внимание!

Так как списки являются тоже ассоциативными массивами, оператор + будет

работать с ними неправильно! Например, в результате слияния списков

аггау(10,20) и array(100,200, 300) получится список array(10,20, 300) —

всего из трех элементов!

Функция date

<? Php

$d=date("d-m-Y");

Echo"Сегодня:$d";

?>

Косвенный перебор элементов массива

Довольно часто при программировании на РНР приходится перебирать все без исключения элементы некоторого массива. Если массив — список, то эта задача, как мы уже знаем, не будет особенно обременительной:

// Пусть $Names — список имен. Распечатаем их в столбик

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

echo $Names[$i]."br";

Везде, где можно, следует избегать помещения имени переменной-массива в кавычки — например, предыдущий пример:

for ($1=0; $i<count($Names); $i++)

echo "$Names[$i] ";

Дело в том, что это, единственный способ, который совместим с РНР версии 3. А что касается четвертой версии, то спокойно можно помещать массивы в строки, заключив их в фигурные скобки вместе с символом $:

$Names=array(

array('name'=>'Vika', 'age'=>20),

array ('name'=>'Kazbek', 'age'=>21)

);

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

echo "($Names[$i] ['age'])";

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

for(Reset($Names); ($k=key($Names)); Next($Names))

echo "Возраст $k — ($Names[$k]) лет ";

Эта конструкция опирается на еще одно свойство ассоциативных массивов в РНР. А именно, кроме того, что массивы являются направленными, в них есть еще и такое понятие, как текущий элемент. Функция Reset () просто устанавливает этот элемент на первую позицию в массиве. Функция key () возвращает ключ, который имеет текущий элемент (если он указывает на конец массива, возвращается пустая строка, что позволяет использовать вызов key () в контексте второго выражения for). Ну а функция Next () просто перемещает текущий элемент на одну позицию вперед.

На самом деле, две простейшие функции, — Reset ( ) и Next ( ), — помимо выполнения своей основной задачи, еще и возвращают некоторые значения, а именно:

  • функция Reset () возвращает значение первого элемента массива (или пустую строку, если массив пуст);

  • функция Next ( ) возвращает значение элемента, следующего за текущим (или пустую строку, если такого элемента нет).

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

for(End($Names); ($k=key($Names)); Prev($Names))

echo "Возраст $k — ($Names[$k]) лет";

По контексту несложно сообразить, как это работает. Функция End ( ) устанавливает позицию текущего элемента в конец массива, a Prev ( ) передвигает ее на один элемент назад.

В РНР имеется функция current ( ) . Она очень напоминает key ( ), только возвращает не ключ, а величину текущего элемента (если он не указывает на конец массива).

Основное достоинство - "читабельность" и ясность кода, а также то, что массив мы можем перебрать как в одну, так и в другую сторону. Однако существуют и недостатки.

Вложенные циклы

Первый недостаток довольно фундаментален: мы не можем одновременно перебирать массив в двух вложенных циклах или функциях. Причина вполне очевидна: второй вложенный for "испортит" положение текущего элемента у первого for'a. К сожалению, эту проблему никак нельзя обойти (разве что сделать копию массива, и во внутреннем цикле работать с ней, но это не очень-то красиво). Однако практика показывает, что такие переборы встречаются крайне редко.

Нулевой ключ

А что, если в массиве встретится ключ 0 (хотя для массивов имен это, согласитесь, маловероятно)? Еще раз посмотрим на первый цикл перебора:

for(Reset($Names); ($k=key($Names)); Next($Names))

echo "Возраст $k – ($Names[$k]) лет";

В этом случае выражение ($k=key ($Names)), естественно, будет равно нулю, и цикл оборвется, чего бы совсем не хотелось.

Именно по этим причинам придуман другой, хотя и менее универсальный, но гораздо более удобный метод перебора массивов.

Прямой перебор массива

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

Классический перебор

Вернемся к примеру, в котором массив $Names хранил связь имен людей и их возрастов. Вот как можно перебрать этот массив при помощи прямого перебора:

for(Reset($Names); list($k,$v)=each($Names); /*пусто*/)

echo "Возраст $k — $v";

В самом начале заголовка цикла мы видим нашу знакомую функцию Reset ( ).

Дальше переменным $k и $v присваивается результат работы функции each (). Третье условие цикла попросту отсутствует (чтобы это подчеркнуть, на его месте комментарий).

Что делает функция each () ? Во-первых, возвращает небольшой массив (даже можно сказать, список), нулевой элемент которого хранит величину ключа текущего элемента массива $Names, а первый — значение текущего элемента. Во-вторых, она продвигает указатель текущего элемента к следующей позиции. Следует заметить, что если следующего элемента в массиве нет, то функция возвращает не список, a false. Именно поэтому она и размещена в условии цикла for. Становится ясно, почему мы не указали третий блок операторов в цикле for: он просто не нужен, ведь указатель на текущий элемент и так смещается функцией each ( ) .

Перебор в стиле РНР 4

Прямой перебор массивов применяется столь часто, что разработчики РНР в четвертой версии языка добавили специальную инструкцию перебора массива — foreach. Вот как с ее помощью можно перебрать и распечатать массив людей:

foreach($Names as $k=>$v) echo "Возраст $k — $v";

Этот способ перебора работает с максимально возможной скоростью — даже быстрее, чем перебор списка при помощи for и числового счетчика.

Замечание

Есть и еще одна причина предпочесть этот вид перебора "связке" цикла for с each(). Дело в том, что при применении foreach мы указываем имя перебираемого массива $Names только в одном месте, так что когда вдруг потребуется это имя изменить, нам достаточно будет поменять его только один раз. Наоборот, использование Reset () и each () заставит в таком случае изменить название переменной в двух местах, что потенциально может привести к ошибке. Представьте, что произойдет, если мы случайно изменим операнд each ( ) , но сохраним параметр Reset ( )!

Списки и строки

Есть несколько функций, которые чрезвычайно часто используются при программировании сценариев. Среди них — функции для разбиения какой-либо строки на более мелкие части (например, эти части разделяются в строке каким-то специфическим символом типа |), и, наоборот, слияния нескольких небольших строк в одну большую, причем не впритык, а вставляя между ними разделитель. Первую из этих возможностей реализует стандартная функция explode ( ) , а вторую — implode ( ) . Рекомендую обратить особое внимание на указанные функции, т. к. они применяются очень часто.

Функция explode ( ) имеет следующий синтаксис:

list explode(string $token, string $Str [, int $limit])

Она получает строку, заданную в ее втором аргументе, и пытается найти в ней подстроки, равные первому аргументу. Затем по месту вхождения этих подстрок строка "разрезается" на части, помещаемые в массив-список, который и возвращается. Если задан параметр $iimit, то учитываются только первые ($iimit-i) участков "разреза". Таким образом, возвращается список из не более чем $ limit элементов. Это позволяет нам проигнорировать возможное наличие разделителя в тексте последнего поля, если мы знаем, что всего полей, скажем, 6 штук. Вот пример:

$st="45972193611 Иванов|Иван|40|ivan@ivanov.com|Текст, содержащий (|) !";

$A=explode("I",$st,6); // Мы знаем, что там только 6 полей!

// теперь $А[0]="Иванов", ... $А[5]= "Текст, содержащий (I)!"

list($Surname,$Name,$Age,$Email,$Tel)=$A; // распределили по переменным

Конечно, строкой разбиения может быть не только один символ, но и небольшая строка. Не перепутать только порядок следования аргументов при вызове функции!

Функция implode () и ее синоним join () производят действие, в точности обратное вызову explode ( ) .

string implode(string $glue, list $List) или

string join(string $glue, list $List)

Они берут ассоциативный массив (обычно это список) $List, заданный в ее первом параметре, и "склеивают" его значения при помощи "строки-клея" $glue во втором параметре. Примечательно, что вместо списка во втором аргументе можно передавать любой ассоциативный массив — в этом случае будут рассматриваться только его значения.

Рекомендуется применять функции implode () и explode (), ибо они работают очень быстро.