Управляющие структуры
Автор: | Артемьев Сергей Игоревич |
ICQ: | 438856621 |
email: | _spin_@bk.ru |
Все скрипты в PHP представляют собой набор различных выражений, которые выполняются последовательно. Выражения можно объединять в группы выражений при помощи т.н. "операторных скобок" "{" и "}". Группы выражений используются в основном вместе с управляющими конструкциями языка PHP.
Управляющие конструкции языка - это наборы служебных слов, позволяющие изменять ход выполнения скрипта. Все конструкции можно условно разделить на конструкции бинарного выбора, множественного выбора, повторения и включения.
Конструкции бинарного (двойственного) выбора позволяют в зависимости от условия выполнить либо первое, либо второе действие. В PHP эти конструкции представлены ключевыми словами if, else, elseif и endif.
Конструкция if позволяет выполнить какое-то действие, если условие истинно. Этот пример читается как "ЕСЛИ условие истинно ТО выполнить выражения".
<?php if(условие) одиночное_выражение; // или if(условие) { несколько; последовательных; выражений; } ?>
Конструкция else используется совместно с if и определяет действие, когда условие ложно. Нижеследующий пример читается как "ЕСЛИ условие истинно ТО выполнить выражения-1 ИНАЧЕ выполнить выражения-2".
<?php if(условие) { выражения-1; } else { выражения-2; } ?>
Конструкция elseif аналогична else, но позволяет создавать цепочки условий и действий. Приведённый ниже пример читается как "ЕСЛИ условие-1 истинно ТО выполнить выражения-1 ИНАЧЕ ЕСЛИ условие-2 истинно ТО выполнить выражения-2 ИНАЧЕ ...".
<?php if(условие-1) { выражения-1; } elseif(условие-2) { выражения-2; } elseif(условие-3) ... ?>
Конструкция endif может использоваться в случае альтерантивной формы записи управляющих конструкций. Отличие альтернативной формы от стандартной в том, что открывающая операторная скобка "{" заменяется на двоеточие ":", закрывающая скобка удалятся, а граница конструкции определяется по ключевому слову endXXX, где XXX - тип конструкции. Например, для связки if...endif...else тип конструкции - "if", значит граница будет определяться по ключевому слову "endif". Сравните:
<?php // Стандартная форма записи: if(условие-1) { выражения-1; } elseif(условие-2) { выражения-2; } else { выражения-3; } // Альтернативная форма записи: if(условие-1): выражения-1; elseif(условие-2): выражения-2; else: выражения-3; endif; ?>
Какой из форм пользоваться - каждый разработчик решает для себя сам, но большинство всё же придерживается стандартной формы записи (т.е. с нормальными операторными скобками "{" и "}")
Конструкция множественного выбора представляет собой компактную форму записи длинных цепочек условий вида "if...elseif....elseif.......else". В PHP такая конструкция носит название switch и имеет достаточно простую форму записи:
<?php switch (выражение/переменная) { case значение-1: выражения-1; break; case значение-2: выражения-2; break; ... default: выражения-N; break; } ?>
Т.е. мы указываем переменную или выражение, после чего указываем возможные значения и действия, соответствующие этим значениям. Все значения, которые мы явно не указали, попадут в блок "default". Замечательная особенность switch - возможность указывать список выражений одновременно для нескольких вариантов. Для этого несколько блоков "case" записываются последовательно, например:
<?php switch (выражение/переменная) { case значение-1: case значение-2: case значение-3: case значение-4: выражения_для_случаев_1_2_3_4; break; case значение-5: выражения_для_случая_5; break; ... default: выражения-N; break; } ?>
Switch очень удобен, когда значения принимают конкретные фиксированные значения. Например, действия водителя на светофоре можно записать так:
<?php $color = 'red'; switch ($color) { case 'красный': echo 'Стоять'; break; case 'красно-желтый': echo 'Приготовиться'; break; case 'желтый': echo 'Остановиться'; break; case 'желтый мигающий': echo 'По обстановке'; break; case 'зелёный': echo 'Ехать'; break; default: // например, светофор выключен echo 'По обстановке'; break; } ?>
Конструкции повторения (организации циклов) предназначены для многократного выполнения одних и тех же выражений. К этим конструкциям относятся while, do-while, for и foreach.
While ("уайл") и do-while ("ду-уайл") предназначены для организации циклов в случаях, когда число повторений заранее неизвестно или может измениться в процессе выполнения цикла. Основой этих конструкций является логическое выражение (условие), а цикл повторяется до тех пор, пока условие истинно (равно TRUE).
Формальная запись конструкций выглядит так:
<?php while (условие) { выражения; } do { выражения; } while (условие); ?>
Главное отличие while от do-while в том, что do-while всегда выполняется хотя бы один раз даже если условие изначально ложно. Например:
<?php $i = 0; while ($i > 0) { echo 'i больше нуля! (цикл while)'; } // не выводится ничего do { echo 'i больше нуля! (цикл do-while)'; } while ($i > 0); // выводится "i больше нуля! (цикл do-while)" ?>
Из примера видно, что пользоваться циклом do-while нужно аккуратно, иначе есть большой риск получить неожиданные и парадоксальные результаты, такие как в нашем примере. Неверное применение циклов очень часто приводит к повялению логических ошибок, которые на порядок сложнее выявить и локализовать, нежели все прочие.
Конструкции while и do-while очень удобно использовать при построчном чтении из файла или обработке результатов запросов к базам данных, т.к. заранее неизвестно, сколько раз надо будет выполнить требуемый набор выражений.
<?php $i = 0; while ($i > 0) { echo 'i больше нуля! (цикл while)'; } // не выводится ничего do { echo 'i больше нуля! (цикл do-while)'; } while ($i > 0); // выводится "i больше нуля! (цикл do-while)" ?>
Следующая конструкция - for ("фор"). Эта конструкция предполагает, что количество итераций цикла заранее известно или вычислимо до начала цикла. Формально for записывается так:
<?php for (переменная; условие; оператор ) { выражения; } ?>
Блок "переменная" описывает переменную-счётчик и её начальное значение, "условие" определяет количество итераций, а "оператор" - действие над переменной-счётчиком ПОСЛЕ каждой итерации. Например, если вам надо вывести 10 раз одну и ту же строку, можно воспользоваться таким кодом:
<?php for ($i = 0; $i < 10; $i++ ) { echo "Копия строки номер " . $i; } ?>
Здесь мы указали, что $i - это переменная счётчик, считать начинаем с нуля, после каждой итерации учеличиваем $i на единицу, продолжаем итерации пока $i меньше 10. Приведённй код цикла функционально эквивалентен следующему (записанному без цикла):
<?php echo "Копия строки номер 0"; echo "Копия строки номер 1"; ... echo "Копия строки номер 9"; ?>
Для цикла for совершенно не обязательно знать количество итераций на этапе написания скрипта. Главное - мы должны суметь вычислить это количество и передать в цикл. Например:
<?php // код можно использовать, например, для // создания навигатора по // страницам каталога товаров // общее количество элементов в каталоге $rows = 100; // количество одновременно отображаемых // элементов на странице $rows_per_page = 16; // вычисляем количество страниц $pages = ceil($rows/$rows_per_page); $page_line = ''; // для каждой страницы создаём соответствующую ссылку for ($i = 0; $i < $pages; $i++ ) { $page_line .= '<a href="?page=' . $i . '">[' . ($i + 1) . ']</a>'; } // выводим готовую строку навигации echo $page_line; // выведет "[1][2][3][4][5][6][7]"; ?>
Последняя конструкция циклов - foreach. Это самая простая и самая своеобразная конструкция из рассмотренных. Записывается она так:
<?php foreach(массив as формат_элемента) { выражения; } ?>
Здесь "массив" - переменная типа array, созданная ранее, а "формат_элемента" - это формальное описание одного элемента массива. Рассмотрим на примерах:
<?php // одномерный не-ассоциативный массив $names = array('Александр', 'Владимир', 'Ярослав'); foreach($names as $single_name) { echo 'имя из массива:' . $name . '<br />\n'; } // одномерный ассоциативный массив $names = array( 'Имя' => 'Александр', 'Фамилия' => 'Владимирович', 'Отчество' => 'Генералов', 'Телефон' => '+7(123)456-78-90'); foreach($names as $param => $value) { echo $param . ': ' . $value . '<br />\n'; } ?>
При использования многомерных массивов в foreach они будут интерпретироваться как вложенные ассоциативные массивы. Если в последнем примере $names будет двумерным массивом, то $param будет содержать номер массива перового уровня, а $value - массив второго уровня. Подробнее о массивах и работе с ними мы поговорим в соответствующем уроке.
Цикл foreach перебирает все элементы массива, независимо от их количества. Недостаток этой конструкции - невозможность модификации элементов массива во время итерации. Связано это с тем, что foreach перед началом цикла создаёт копию массива, которая уничтожается после окончания цикла. Следовательно, все изменения при выходе из цикла теряются. Этот недостаток был исправлен в PHP версии 5 и выше за счет добавления ссылки на элемент данных:
<?php // одномерный не-ассоциативный массив $names = array('Александр', 'Владимир', 'Ярослав'); foreach($names as &$single_name) { $name .= 'ович'; } echo implode(', ', $names); // в PHP до 5 версии выведет: // "Александр, Владимир, Ярослав" // в PHP 5 выведет: // "Александрович, Владимирович, Ярославович" ?>
Специально для управления исполнением циклов и скриптов в PHP существует несколько ключевых слов: break, continue и return.
break применяется внутри циклов и служит для немендленного прекращения итераций цикла. Управление передаётся на следующее после цикла выражение. Например, можно прервать цикл при возникновении определённых условий:
<?php $names = ('Ярослав', 'Александр', ...); foreach($i = 0; $i < 100; $i++) { if($names[$i] == 'Александр') break; } echo 'Имя "Александр" стоит на ' . $i . ' позиции'; // выведет: // 'Имя "Александр" стоит на 2 позиции' ?>
break очень полезен в случае поиска нужного элемента массива, т.к. можно остановить поиск сразу после нахождения нужного элемента и не лопатить заведомо пустой остаток массива.
Следующее ключевое слово - continue. Предназначено для немедленного перехода к следующей итерации. Например, можно преобразовать предыдущий пример следующим образом:
<?php $names = ('Ярослав', 'Александр', ...); foreach($i = 0; $i < 100; $i++) { if($names[$i] != 'Александр') continue; echo 'Имя "Александр" стоит на ' . $i . ' позиции'; } // выведет: // 'Имя "Александр" стоит на 2 позиции' ?>
Такой цикл переберёт все элементы массива и выполнит код "echo ..." только для тех элементов, где значение равно "Александр". Такое построение цикла удобно применять для случаев, когда выражения должны быть применены к нескольким элемента массива.
Последнее ключевое слово - return. Оно предназначено для немедленного выхода из функции и возврата значения (при необходимости). Подробнее об использовании return мы поговорим при рассмотрении функций.
Последняя группа конструкций - конструкции включения. Они предназначены для включения в текст скрипта каких-либо данных и кода, находящихся в другом файле. Всего существует четыре варианта: include, include_once, require, require_once.
Конструкции с приставкой "_once" отличаются от прочих тем, что гарантируют однократное включение файла в рамках всех задействованых файлов. Т.е. если у вас есть 10 файлов и в каждом необходимо подключить файл с описанием, например, класса, то при использовании обычных require или include PHP выдаст ошибку "недопустимо повторное обявление класса" уже на второй встретившейся команде включения. С другой стороны, include_once или require_once предварительно проверят предыдущие включения, и если файл уже был подключен - повторно подключать его не будут.
Отличие между include и require заключено в поведении при отсутсвующем файле для подключения. Если include или inclide_once не находят указанный файл, то выдают предупреждение для пользователя. А вот require и require_once генерируют ошибку и прекращают дальнейшее выполнение скрипта.
Формат всех четырёх конструкций практически одинаков. Имена подключаемых файлов можно записывать как в полной, так и сокращённой форме.
<?php include('engine/filename.php'); include_once('myclass.class.php'); require('./../utils/db.php'); require_once('./../config/config_db.inc'); ?>
Я бы рекомендовал максимально часто пользоваться require_once с относительными путями к файлам. Во-первых, это гарантирует наличие всех требуемых файлов, а во-вторых - делает невозможными ошибки повторного объявления классов и переменных. А в третьих - увеличивает гибкость и переносимость кода. В некоторых случаях грамотно построеная система подключаемых файлов значительно экономит силы и время разработчика, т.к. позволяет повторно использовать многие фрагменты кода.