Глава 3. Выражения, операторы и управляющие конструкции в PHP

В этой главе представлены некоторые аспекты, играющие исключительно важную роль в любом языке программирования, — а именно, выражения, операторы и управляющие конструкции. Этот материал необходим в первую очередь при создании больших и сложных приложений РНР. Если вы уже знакомы с такими языками, как С и Java, эта глава всего лишь напомнит известные вам понятия. Если же вы впервые встречаетесь с этими терминами и понятиями, которые они обозначают, знание материала этой главы будет безусловно необходимо для понимания остальных глав книги.

Выражения

Выражение описывает некоторое действие, выполняемое в программе. Каждое выражение состоит по крайней мере из одного операнда и одного или нескольких операторов. Прежде чем переходить к примерам, демонстрирующим использование выражений, необходимо поближе познакомиться с операторами и операндами.

Операнды

Операнд представляет собой некоторую величину, обрабатываемую в программе. Операнды могут относиться к любому типу данных, представленному в главе 2. Вероятно, вы уже знакомы с концепциями обработки и использования операндов не только в повседневных математических вычислениях, но и по прежнему опыту программирования. Примеры операндов:

$а++; // $а - операнд
$sum = $val1 + $val2; // $sum. $val1 и $val2 - операнды

Операторы

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

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

Таблица 3.1. Операторы РНР

ОператорАссоциативностьЦель
( )НетИзменение приоритета
newНетСоздание экземпляров объектов
! ~ПраваяЛогическое отрицание, поразрядное отрицание
++ --ПраваяИнкремент, декремент
@ПраваяМаскировка ошибок
/ * %ЛеваяДеление, умножение, остаток
+ - .ЛеваяСложение, вычитание, конкатенация
<< >>ЛеваяСдвиг влево, сдвиг вправо (поразрядный)
< <= > >=НетМеньше, меньше или равно, больше, больше или равно
== != === <>НетРавно, не равно, идентично, не равно
& ^ |ЛеваяПоразрядные операции AND, XOR и OR
&& ||ЛеваяЛогические операции AND и OR
?:ПраваяТернарный оператор
= += *= /= .=ПраваяОператоры присваивания
%= &= |= ^=ПраваяОператоры присваивания
<<= >>=ПраваяОператоры присваивания сдвига
AND XOR ORЛеваяЛогические операции AND, XOR и OR

После знакомства с концепциями операторов и операндов следующие примеры выражений выглядят значительно понятнее:

$a = 5; // Присвоить целое число 5 переменной $a
$a = "5"; // Присвоить строковую величину "5" переменной $a
$sum = 50 + $some_int; // Присвоить сумму 50 + $some_int переменной $sum
$wine = "Zinfandel"; // Присвоить строку "Zinfandel" переменной $wine
$inventory++; // Увеличить значение $inventory на 1

Объединяя операторы и операнды, вы получите более сложные выражения для выполнения нетривиальных вычислений. Пример:

$total_cost = $cost + ($cost * 0.06); // прибавить к цене шести процентный налог

Приоритет операторов

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

$total_cost = $cost + $cost * 0.06;

Приведенная команда эквивалентна следующей:

$total_cost = $cost + ($cost * 0.06);

Это объясняется тем, что оператор умножения обладает более высоким приоритетом по сравнению с оператором сложения.

Ассоциативность операторов

Ассоциативность оператора определяет последовательность выполнения операторов с одинаковым приоритетом (см. табл. 3.1). Выполнение может происходить в двух направлениях: либо слева направо, либо справа налево. При ассоциативности первого типа операции, входящие в выражение, выполняются слева направо. Например, команда

$value = 3*4*5*7*2;

эквивалентна следующей команде:

$value = ((((3 * 4) * 5) * 7) * 2);

Результат вычислений равен 840. Это объясняется тем, что оператор умножения (*) обладает левосторонней ассоциативностью. Операторы с правосторонней ассоциативностью и одинаковым приоритетом обрабатываются справа налево. Например, фрагмент

$с = 5;
$value = $а - $b - $с;

эквивалентен фрагменту

$c = 5;
$value = ($а - ($b + $с));

При обработке этого выражения переменным $value, $a, $b и $с будет присвоено значение 5. Это объясняется тем, что оператор присваивания (=) обладает правосторонней ассоциативностью.

Математические операторы

Математические операторы (табл. 3.2) предназначены для выполнения различных математических операций и часто применяются в большинстве программ РНР. К счастью, их использование обходится без проблем.

Таблица 3.2. Математические операторы

Пример Название Результат
$а + $b Сложение Сумма $а и $b
$а-$b Вычитание Разность $а и $b
$а*$b Умножение Произведение $а и $b
$а/$b Деление Частное от деления $а на $b
$а % $b Остаток Остаток от деления $а на $b

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

Операторы присваивания

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

Таблица 3.3. Операторы присваивания

ПримерНазваниеРезультат
$а = 5;ПрисваиваниеПеременная $а равна 5
$а += 5;Сложение с присваиваниемПеременная $а равна сумме $а и 5
$а *= 5;Умножение с присваиваниемПеременная $а равна произведению $а и 5
$а/=5;Деление с присваиваниемПеременная $а равна частному от деления $а на 5
$а .= 5;Конкатенация с присваиваниемПеременная $а равна конкатенации $а и 5

Умеренное использование операторов присваивания обеспечивает более наглядный и компактный код.

Строковые операторы

Строковые операторы РНР (табл. 3.4) обеспечивают удобные средства конкатенации (то есть слияния) строк. Существует два строковых оператора: оператор конкатенации (.) и оператор конкатенации с присваиванием (.=), описанный в предыдущем разделе «Операторы присваивания».

Конкатенацией называется объединение двух и более объектов в единое целое.

Таблица 3.4. Строковые операторы

ПримерНазваниеРезультат
$a = "abc"."def"КонкатенацияПеременной $а присваивается результат конкатенации $а и $b
$a - "ghijkl"Конкатенация с присваиваниемПеременной $а присваивается результат конкатенации ее текущего значения со строкой "ghijkl"

Пример использования строковых операторов:

// $а присваивается строковое значение "Spaghetti & Meatballs" $а = "Spaghetti" . "& Meatballs"

// $а присваивается строковое значение "Spaghetti & Meatballs are delicious" $a .= "are delicious";

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

Операторы инкремента и декремента

Удобные вспомогательные операторы инкремента (++) и декремента (--), приведенные в табл. 3.5, делают программу более наглядной и обеспечивают укороченную запись для увеличения или уменьшения текущего значения переменной на 1.

Таблица 3.5. Операторы инкремента и декремента

ПримерНазваниеРезультат
++$a, $a++ИнкрементПеременная $a увеличивается на 1
--$a, $a--ДекрементПеременная $a уменьшается на 1

Интересный факт: эти операторы могут располагаться как слева, так и справа от операнда. Действия, выполняемые оператором, зависят от того, с какой стороны от операнда он находится. Рассмотрим следующий пример:

$inventory = 15; // Присвоить $inventory целое число 15
$old_inv = $inventory--; // СНАЧАЛА присвоить $old_inv значение $inventory, а ЗАТЕМ уменьшить $inventory
$orig_inventory = ++$inventory; // СНАЧАЛА увеличить $inventory, а ЗАТЕМ присвоить увеличенное значение $inventory переменной $orig_inventory

Как видите, расположение операторов инкремента и декремента оказывает сильное влияние на результат вычислений.

Логические операторы

Логические операторы (табл. 3.6) наряду с математическими операторами играют важную роль в любом приложении РНР, обеспечивая средства для принятия решений в зависимости от значения переменных. Логические операторы позволяют управлять порядком выполнения команд в программе и часто используются в управляющих конструкциях (таких, как условная команда if, а также циклы for и while).

Таблица 3.6. Логические операторы

ПримерНазваниеРезультат
$a && $bКонъюнкцияИстина, если истинны оба операнда
$a AND $bКонъюнкцияИстина, если истинны оба операнда
$a И $bДизъюнкцияИстина, если истинен хотя бы один из операндов
$a OR $bДизъюнкцияИстина, если истинен хотя бы один из операндов
!$aОтрицаниеИстина, если значение $a ложно
NOT !$aОтрицаниеИстина, если значение $a ложно
$a XOR $bИсключающая дизъюнкцияИстина, если истинен только один из операндов

Логические операторы часто используются для проверки результата вызова функций:

file_exists("filename.txt") OR print "File does not exist!";

Возможен один из двух вариантов:

Операторы равенства

Операторы равенства (табл. 3.7) предназначены для сравнения двух величин и проверки их эквивалентности.

Таблица 3.7. Операторы равенства

ПримерНазваниеРезультат
$a == $bПроверка равенстваИстина, если $a и $b равны
$a != $bПроверка неравенстваИстина, если $a и $b не равны
$a === $bПроверка идентичностиИстина, если $a и $b равны и имеют одинаковый тип

Даже опытные программисты часто допускают одну распространенную ошибку — они пытаются проверять равенство двух величин, используя всего один знак равенства (например, $а = $b). Помните, при такой записи значение $b присваивается $а, и желаемый результат не будет достигнут.

Операторы сравнения

Операторы сравнения (табл. 3.8), как и логические операторы, позволяют управлять логикой программы и принимать решения при сравнении двух и более переменных.

Таблица 3.8. Операторы сравнения

ПримерНазваниеРезультат
$a < $bМеньшеИстина, если переменная $a меньше $b
$a > $bБольшеИстина, если переменная $a больше $b
$a <= $bМеньше или равноИстина, если переменная $a меньше или равна $b
$a >= $bБольше или равноИстина, если переменная $a больше или равна $b
($a-12)?5: -1Тернарный операторЕсли переменная $a равна 12, возвращается значение 5, а если не равна — возвращается 1

Обратите внимание: операторы сравнения предназначены для работы только с числовыми значениями. Хотя возникает искушение воспользоваться ими для сравнения строк, результат, скорее всего, окажется неверным. В РНР существуют стандартные функции для сравнения строковых величин. Эти функции подробно рассматриваются в главе 8.

Поразрядные операторы

Поразрядные операторы выполняют операции с целыми числами на уровне отдельных битов, составляющих число. Чтобы лучше понять принцип их работы, необходимо иметь хотя бы общее представление о двоичном представлении десятичных чисел. В табл. 3.9 приведены примеры десятичных чисел и соответствующих им двоичных представлений.

Таблица 3.9. Десятичные числа и их двоичные представления

Десятичное целоеДвоичное представление
210
5101
101010
121100
14510010001
1 452 0121011000100111111101100

Поразрядные операторы, перечисленные в табл. 3.10, представляют собой особый случай логических операторов, однако они приводят к совершенно иным результатам.

Таблица 3.10. Поразрядные операторы

ПримерНазваниеРезультат
$а&$bКонъюнкцияС битами, находящимися в одинаковых разрядах $а и $b, выполняется операция конъюнкции
$а|$ЬДизъюнкцияС битами, находящимися в одинаковых разрядах $а и $b, выполняется операция дизъюнкции
$а^$bИсключающаяС битами, находящимися в одинаковых разрядах $а и $b, выполняется операция исключающей дизъюнкции
~$bОтрицаниеВсе разряды переменной $b инвертируются
$а << $bСдвиг влевоПеременной $а присваивается значение $b, сдвинутое влево на два бита
$а >> $bСдвиг вправоПеременной $а присваивается значение $b, сдвинутое вправо на два бита

Управляющие конструкции

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

Проверка условий

Управляющие конструкции обычно проверяют условия на истинность или ложность, и в зависимости от результата проверки выполняется то или иное действие. Рассмотрим выражение $а == $b. Это выражение истинно, если $а равно $b, и ложно в противном случае. Результат истинного выражения считается равным 1, а результат ложного выражения равен 0. Рассмотрим следующий фрагмент:

$а = 5;
$b = 5;
print $а == $b;

В результате выводится значение 1. Если изменить $а или $Ь и присвоить переменной значение, отличное от 5, выводится 0.

if

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

if (выражение) {
    блок
}

и

if (выражение) {
    блок
} else {
    блок
}

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

if ($cooking_weight < 200) {
    print "This is enough pasta (< 200g) for 1-2 people";
} else {
    print "That's a lot of pasta. Having a party perhaps?";
}

Если в результате проверки условия выполняется всего одна команда, фигурные скобки не обязательны:

if ($cooking_weight < 100) print "Are you sure this is enough?";

elseif

Команда elseif добавляет в управляющую конструкцию if дополнительный уровень проверки и увеличивает количество условий, на основании которых принимается решение:

if (выражение) {
    блок
} elseif (выражение) {
    блок
}

В PHP существует альтернативное представление команды `elseif` — в виде двух отдельных слов `else if`. Оба варианта приводят к одинаковым результатам, а альтернативное представление поддерживается исключительно для удобства. Команда `elseif` особенно полезна в тех случаях, когда происходит последовательное уточнение проверяемых условий. Обратите внимание: условие `elseif` вычисляется лишь в том случае, если все предшествующие условия `if` и `elseif` оказались ложными.

if ($cooking_weight < 200) {
    print "This is enough pasta (< 200g) for 1-2 people";
} elseif ($cooking_weight < 500) {
    print "That's a lot of pasta. Having a party perhaps?";
} else {
    print "Whoa! Who are you cooking for, a football team?";
}

Вложенные команды if

Вложение команд if обеспечивает максимальный контроль над проверкой условий. Давайте исследуем эту возможность, усовершенствовав пример из предыдущих разделов. Предположим, вес продукта должен проверяться лишь в том случае, если речь идет о пасте (макаронных изделиях):

// Проверить значение $pasta
if ($food == "pasta") {
    // Проверить значение $cooking_weight
    if ($cooking_weight < 200) {
        print "This is enough pasta (< 200g) for 1-2 people";
    } elseif ($cooking_weight < 500) {
        print "That's a lot of pasta. Having a party perhaps?";
    } else {
        print "Whoa! Who are you cooking for, a football team?";
    }
}

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

Вычисление нескольких условий

При выборе логики работы программы в управляющей структуре можно проверять комбинацию сразу нескольких условий:

if ($cooking_weight < 0) {
    print "Invalid cooking weight!";
}
if (($cooking_weight > 0) && ($cooking_weight < 200)) {
    print "This is enough pasta (< 200g) for 1-2 people";
} elseif (($cooking_weight > 200) && ($cooking_weight < 500)) {
    print "That's a lot of pasta. Having a party perhaps?";
} else {
    print "Whoa! Who are you cooking for, a football team?";
}

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

Альтернативное ограничение блоков

В управляющих структурах используются специальные ограничители, определяющие границы блоков. Фигурные скобки { } уже упоминались выше. Для удобства программистов в PHP поддерживается альтернативный формат ограничения блоков:

if (выражение) :
    блок
else :
    блок
endif;

Следовательно, две приведенные ниже команды if полностью эквивалентны:

if ($а == $b) {
    print "Equivalent values!";
}

if ($a == $b) :
    print "Equivalent values!";
endif;

Цикл while ...

Конструкция while предназначена для многократного (циклического) выполнения блока команд. Блок команды while выполняется до тех пор, пока условие цикла остается истинным. Общая форма цикла while выглядит так:

while (выражение) {
    блок
}

Рассмотрим использование цикла while на примере вычисления факториала (n!), где n = 5:

$n = 5;
$nсору = $n;
$factorial = 1; // Установить начальное значение факториала
while ($n > 0) :
    $factorial - $n * $factorial;
    $n--; // Уменьшить $n на 1
endwhile;

print "The factorial of $ncopy is $factorial.";

Программа выводит следующий результат:

The factorial of 5 is 120.

В этом примере $n уменьшается в конце каждой итерации. Условие цикла не должно быть истинным в тот момент, когда переменная $n станет равна 0, поскольку величина $factorial умножится на 0 — конечно, этого быть не должно.

В приведенном примере условие цикла следовало бы оптимизировать и привести его к виду $n > 1, поскольку умножать $factorial на 1 бессмысленно — число от этого не изменится. Хотя ускорение работы программы будет ничтожно малым, такие факторы всегда принимаются во внимание с ростом объема и сложности программ.

Цикл do ... while

Цикл do...while работает почти так же, как и цикл while, описанный в предыдущем разделе, однако в do...while условие проверяется не в начале, а в конце каждой итерации. Учтите, что цикл do...while всегда выполняется хотя бы один раз, а цикл while может вообще не выполняться, если перед входом в цикл условие окажется ложным:

do {
    блок
} while (выражение);

Давайте пересмотрим пример с вычислением факториала и перепишем его с использованием конструкции do...while:

$n = 5;
$ncopy = $n;
$factorial = 1; // Установить начальное значение факториала
do {
    $factorial = $n * $factorial;
    $n--; // Уменьшить $n на 1
} while ($n > 0);
    
print "The factorial of $ncopy is $factorial.";

При выполнении этого примера будет получен тот же результат, что и при выполнении его прототипа из предыдущего раздела.

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

for

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

for (инициализация; условие; приращение) {
    блок
}

Условная часть цикла for, на самом деле, состоит из трех компонентов. Инициализация выполняется всего один раз и определяет начальное значение управляющей переменной цикла. Условие проверяется в начале каждой итерации и определяет, должна ли выполняться текущая итерация или нет. Наконец, приращение определяет изменение управляющей переменной при каждой итерации. Возможно, термин «приращение» в данном случае неточен, поскольку переменная может как увеличиваться, так и уменьшаться в соответствии с намерениями программиста. Следующий пример демонстрирует простейший случай применения цикла for:

for ($i = 10; $i <= 100; $i += 10) {
    // Обратная косая черта предотвращает
    print "\$i = $i <br>";
}

Выполнение этого фрагмента дает следующий результат:

$i = 10
$i = 20
$i = 30
$i = 40
$i = 50
$i = 60
$i = 70
$i = 80
$i = 90
$i = 100

В этом примере управляющая переменная $i инициализируется значением 10. Условие заключается в том, что цикл продолжается до тех пор, пока $i не достигнет или не превысит пороговую величину 100. Наконец, при каждой итерации значение $i увеличивается на 10. В результате команда print выполняется 10 раз, каждый раз выводя текущее значение $i. Обратите внимание: для увеличения $i на 10 используется оператор сложения с присваиванием. Для этого есть веские причины, поскольку циклы for в PHP не поддерживают более традиционную запись $i = $i + 10.

Кстати, этот пример можно записать и в другом виде, но с теми же результатами:

for ($i = 10; $i <= 100; print "\$i - $i <br>" . $i += 10);

Многие новички не понимают, зачем создавать несколько разновидностей циклов в языке программирования, будь то PHP или какой-нибудь другой язык. Почему нельзя обойтись одной циклической конструкцией? Дело в том, что у цикла for существует несколько специфических особенностей.

Например, вы можете инициализировать несколько переменных одновременно, разделяя команды инициализации запятыми:

for ($x = 0, $y = 0; $x + $y < 10; $x++) {
    $y += 2; // Увеличить $у на 2
    print "\$y = $y <br>"; // Вывести значение $у
    $sum = $x + $y;
    print "\$sum = $sum <br>"; // Вывести значение $sum
}

Результат:

$y = 2
$sum = 2
$sum = 5
$y = 6
$sum = 8
$y = 8
$sum = 11

Этот пример выводит текущие значения $y и суммы $x и $y. Как видно из приведенных результатов, выводится значение $sum = 11, хотя эта сумма выходит за границы условия цикла ($x + $y < 10). Это происходит из-за того, что при входе в данную итерацию переменная $y была равна 6, а переменная $x была равна 2. Значения переменных соответствовали условию цикла, поэтому $x и $y были присвоены новые значения, в результате чего была выведена сумма. При очередной проверке условия сумма 11 превысила пороговое значение 10 и цикл завершился.

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

$x = 5;
for (; ; $x += 2) {
    print " $x ";
    if ($x == 15) {
        break; // Выйти из цикла for
    }
}

Результат выглядит так:

5 7 9 11 13 15

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

foreach

Конструкция foreach представляет собой разновидность for, включенную в язык для упрощения перебора элементов массива. Существуют две разновидности команды foreach, предназначенные для разных типов массивов:

foreach ($массив as $элемент) {
    блок
}
foreach ($массив as $ключ => $элемент) {
    блок
}

Например, при выполнении следующего фрагмента:

$menu = array("pasta", "steak", "potatoes", "fish", "fries");
foreach ($menu as $item) {
    print "$item <br>";
}

будет выведен следующий результат:

pasta
steak
potatoes
fish
fries

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

Второй вариант используется при работе с ассоциативными массивами:

$wine_inventory = array (
    "merlot" => 15,
    "zinfandel" => 17,
    "sauvignon" => 32
);

foreach ($wine_inventory as $i => $item_count) {
    print "$item_count bottles of $i remaining<br>";
}

В этом случае результат выглядит так:

15 bottles of merlot remaining
17 bottles of zinfandel remaining
32 bottles of sauvignon remaining

Как видно из приведенных примеров, конструкция foreach заметно упрощает работу с массивами. За дополнительной информацией о массивах обращайтесь к главе 5.

switch

Принцип работы конструкции switch отчасти напоминает if — результат, полученный при вычислении выражения, проверяется по списку потенциальных совпадений.

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

switch ($выражение) {
    case $условие:
        блок
        break;
    case $условие:
        блок
        break;
    ...
    default:
        блок
}

Проверяемое условие указывается в круглых скобках после ключевого слова switch. Результат его вычисления последовательно сравнивается с условиями в секциях case. При обнаружении совпадения выполняется блок соответствующей секции. Если совпадение не будет обнаружено, выполняется блок необязательной секции default.

$user_input = "recipes"; // Команда, выбранная пользователем
switch ($user_input) {
    case "search":
        print "Let's perform a search!";
        break;
    case "dictionary":
        print "What word would you like to look up?";
        break;
    case "recipes":
        print "Here is a list of recipes...";
        break;
    default:
        print "Here is the menu...";
        break;
}

Как видно из приведенного фрагмента, команда switch обеспечивает четкую и наглядную организацию кода. Переменная, указанная в условии switch (в данном примере — $user_input), сравнивается с условиями всех последующих секций case. Если значение, указанное в секции case, совпадает с значением сравниваемой переменной, выполняется блок этой секции. Команда break предотвращает проверку дальнейших секций case и завершает выполнение конструкции switch. Если ни одно из проверенных условий не выполняется, активизируется необязательная секция default. Если секция default отсутствует и ни одно из условий не выполняется, команда switch просто завершается и выполнение программы продолжается со следующей команды.

Вы должны помнить, что при отсутствии в секции case команды break (см. следующий раздел) выполнение switch продолжается со следующей команды до тех пор, пока не встретится команда break или не будет достигнут конец конструкции switch. Следующий пример демонстрирует последствия отсутствия забытой команды break: $value = 0.4;

switch ($value) {
    case 0.4:
        print "Значение равно 0.4<br>";
        break;
    case 0.6:
        print "Значение равно 0.6<br>";
        break;
    case 0.3:
        print "Значение равно 0.3<br>";
        break;
    default:
        print "Вы не выбрали значение!";
        break;
}

Результат выглядит так:

Значение равно 0.4

Отсутствие команды break привело к тому, что была выполнена не только команда print в той секции, где было найдено совпадение, но и команда print в следующей секции. Затем выполнение команд конструкции switch прервалось из-за команды switch, следующей за второй командой print.

Выбор между командами switch и if практически не влияет на быстродействие программы. Решение об использовании той или иной конструкции является скорее личным делом программиста.

break

Команда break немедленно прерывает выполнение той конструкции while, for или switch, в которой она находится. Эта команда уже упоминалась в предыдущем разделе, однако прерывание текущего цикла не исчерпывает возможностей команды break. В общем виде синтаксис break выглядит так: break n;

Необязательный параметр n определяет количество уровней управляющих конструкций, завершаемых командой break. Например, если команда break вложена в две команды while и после break стоит цифра 2, происходит немедленный выход из обоих циклов. По умолчанию значение n равно 1; выход на один уровень может обозначаться как явным указанием 1, так и указанием команды break без параметра. Обратите внимание: команда if не относится к числу управляющих конструкций, прерываемых командой break. Об этом следует помнить при использовании необязательного параметра n.

Рассмотрим пример использования команды break в цикле foreach:

$arr = array(14, 12, 128, 34, 5);
$magic_number = 128;
foreach ($arr as $val) :
if ($val == $magic_number) :
print "Магическое число есть в массиве!";
break;
endif;
print "val is $val <br>";
endforeach;

Если значение $magic_number присутствует в массиве $arr (как в приведенном примере), поиск прерывается. Результат выглядит так:

val is 14
val is 12
Магическое число есть в массиве!

Приведенный пример всего лишь демонстрирует использование команды break. В PHP существует стандартная функция in_array(), предназначенная для поиска заранее заданной величины в массиве; эта функция подробно описана в главе 5.

continue

Остается рассмотреть еще одну управляющую конструкцию PHP — continue. При выполнении команды continue в цикле пропускаются все оставшиеся команды текущей итерации и немедленно начинается новая итерация. Синтаксис команды continue в общем виде: continue n;

Необязательный параметр n указывает, на сколько уровней внешних циклов распространяется действие continue.

Рассмотрим пример использования команды continue. Допустим, вы хотите сосчитать простые числа в интервале от 0 до некоторой заданной границы. Простоты ради предположим, что у нас имеется функция is_prime(), которая проверяет, является число простым или нет:

$boundary = 558;
for ($i = 0; $i <= $boundary; $i++) :
if (!is_prime($i)) :
continue;
endif;
$prime_counter++;
endfor;

Если проверяемое число является простым, блок команды if обходится и переменная $prime_counter увеличивается. В противном случае выполняется команда continue, в результате чего происходит немедленный переход в начало следующей итерации.

Использование continue в длинных и сложных алгоритмах приводит к появлению запутанного и невразумительного кода. В подобных случаях использовать continue не рекомендуется.

Команда continue не является безусловно необходимой в программах, поскольку аналогичного эффекта можно добиться при помощи команды if.

Проект: календарь событий

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

Информация о событиях хранится в обычном текстовом файле и выглядит примерно так:

July 21, 2000|8 p. m.|Cooking With Rasmus|PHP creator Rasmus Lerdorf discusses the wonders of cheese.

July 23, 2000|11 a. m.|Boxed Lunch|Valerie researches the latest ham sandwich making techniques (documentary)

July 31, 2000|2:30p.m.|Progressive Gourmet|Forget the Chardonnay: iced tea is the sophisticated gourmet's beverage of choice.

August 1, 2000|7 p.m.|Coder's Critique|Famed Food Critic Brian rates NYC's hottest new Internet cafes.

August 3, 2000|6 p.m.|Australian Algorithms|Matt studies the alligator's diet.

На рис. 3.1 изображен результат работы сценария PHP, приведенного в листинге 3.1.

Примерный вид календаря

Рис. З.1. Примерный вид календаря

Прежде чем переходить к подробному анализу кода, потратьте немного времени на изучение алгоритма:

  1. Открыть файл, содержащий информацию о событиях.
  2. Разделить каждую строку на 4 элемента: дату, время, название и краткое описание мероприятия.
  3. Отформатировать и вывести данные.
  4. Закрыть файл.

Листинг 3.1. Сценарий для вывода содержимого events.txt в браузере

<?php
// Приложение: календарь
// Назначение: чтение и анализ содержимого файла
// с последующим форматированием для вывода в браузере

// Открыть файловый манипулятор $events для файла events.txt
$events = fopen("events.txt", "r");

print "<table border = 0 width = 250>";
print "<tr><td valign=top>";
print "<h3>Events Calendar:</h3>";

// Читать, пока не будет найден конец файла
while (!feof($events)) :
    // Прочитать следующую строку файла
    $event = fgets($events, 4096);
    // Разделить компоненты текущей строки на элементы массива
    $event_info = explode("|", $event);
    // Отформатировать и вывести информацию о событии
    print "$event_info[0] ( $event_info[1] ) <br>";
    print "<b>$event_info[2]</b> <br>";
    print "$event_info[3] <br> <br>";
endwhile;

// Завершить таблицу
print "</td></tr>
    </table>";

fclose($events);
?>

Этот короткий пример убедительно доказывает, что PHP позволяет даже неопытным программистам создавать реальные приложения с минимальными усилиями и затратами времени. Если какие-нибудь из представленных концепций покажутся непонятными, не огорчайтесь — на самом деле они очень просты и будут подробно описаны в следующих главах. А если вам не терпится узнать побольше об этих вопросах, обратитесь к главе 7 «Файловый ввод/вывод и файловая система» и главе 8 «Строки и регулярные выражения» поскольку большая часть незнакомого синтаксиса описана именно там.

Итоги

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

В первых трех главах книги вы познакомились с базовыми компонентами языка РНР. Остальные пять глав первой части расширяют этот материал; в них вы найдете дополнительную информацию о работе с массивами, объектно-ориентированных возможностях, файловом вводе/выводе и строковых операциях РНР. Весь этот материал готовит читателя ко второй части книги, причем особое внимание уделяется средствам РНР, часто используемым при построении приложений. Итак, держитесь покрепче и не сходите с дистанции!