Управляющие структуры
| Автор: | Артемьев Сергей Игоревич |
| 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 с относительными путями к файлам. Во-первых, это гарантирует наличие всех требуемых файлов, а во-вторых - делает невозможными ошибки повторного объявления классов и переменных. А в третьих - увеличивает гибкость и переносимость кода. В некоторых случаях грамотно построеная система подключаемых файлов значительно экономит силы и время разработчика, т.к. позволяет повторно использовать многие фрагменты кода.