Нетрадиционное использование do-while и break
Есть один интересный побочный эффект, который дает нам инструкция break
, и который довольно удобно использовать для обхода "лишних" операторов. Необходимость такого обхода возникает довольно часто, причем именно при программировании сценариев. Рассмотрим соответствующий пример:
. . .
$WasError=0; // индикатор ошибки — если не 0, то была ошибка
// Если нажали кнопку Submit (с именем $doSubmit)...
if(@$doSubmit) do {
// Проверка входных данных
if(неправильное имя пользователя) { $WasError=1; break; }
. . . и т. д.
if(неправильные данные) { $WasError=1; break; }
. . . и т. д.
// Данные в порядке. Обрабатываем их.
выполняем действия;
выводим результат;
завершаем сценарий;
} while(0);
. . .
// Выводим форму, через которую пользователь будет запускать этот сценарий,
и, возможно, отображаем сообщение об ошибке в случае, если $WasError!=0.
Здесь представлен наиболее обычный способ для организации сценариев-диалогов. Запустив сценарий без параметров, пользователь видит форму с приглашением ввести свое имя, пароль и некоторые другие данные. При нажатии кнопки запускается тот же самый сценарий, который определяет, что была нажата кнопка doSubmit
, и первым делом проверяет имя и пароль. Если они заданы неверно, то отображается опять наша форма (и где-нибудь красным цветом сообщение об ошибке), в противном случае сценарий завершается и выдает страницу с результатом.
Мы видим, что указанный алгоритм можно реализовать наиболее удобно, имея какой-то способ обрывания блока "проверки-и-завершения" и возврата к выводу формы заново. Как раз это и делает конструкция
if(что_то) do { ... } while(0);
Очевидно, что тело цикла do-while
выполняется в любом случае только один раз (так как выражение в while
всегда ложно). Тем не менее, такой "вырожденный" цикл мы можем использовать для быстрого выхода из него посредством break
. Многие сразу возразят, что в таких случаях удачнее будет задействовать функции и оператор return
. Однако в PHP как раз это довольно неудобно, поскольку для того, чтобы из функции добраться до глобальной переменной (коей является любой элемент формы), нужно проделать несколько дополнительных шагов. Это, конечно, недостаток PHP, и о нем мы поговорим чуть позже.
Цикл foreach
Данный тип цикла предназначен специально для перебора всех элементов массива и был добавлен только в четвертой версии языка PHP. Выглядит он следующим образом:
foreach(массив as $key=>$value)
команды;
Здесь команды циклически выполняются для каждого элемента массива, при этом очередная пара ключ=>значение
оказывается в переменных $key
и $value
. Давайте рассмотрим пример, где покажем, как мы можем отобразить содержимое всех глобальных переменных при помощи foreach
:
<?php
foreach($GLOBALS as $k=>$v)
echo "<b>$k</b> => <tt>$v</tt><br>\n";
?>
У цикла foreach
имеется и другая форма записи, которую следует применять, когда нас не интересует значение ключа очередного элемента. Выглядит она так:
foreach(массив as $value)
команды;
В этом случае доступно лишь значение очередного элемента массива, но не его ключ. Это может быть полезно, например, для работы с массивами-списками.
Внимание! Цикл foreach
оперирует не исходным массивом, а его копией. Это означает, что любые изменения, которые вносятся в массив, не могут быть "видны" из тела цикла. Что позволяет, например, в качестве массива использовать не только переменную, но и результат работы какой-нибудь функции, возвращающей массив (в этом случае функция будет вызвана всего один раз — до начала цикла, а затем работа будет производиться с копией возвращенного значения).
Конструкция switch-case
Часто вместо нескольких расположенных подряд инструкций if-else
целесообразно воспользоваться специальной конструкцией switch-case
:
switch(выражение) {
case значение1: команды1; [break;]
case значение2: команды2; [break;]
. . .
case значениеN: командыN; [break;]
[default: команды_по_умолчанию; [break]]
}
Делает она следующее: вычисляет значение выражения (пусть оно равно, например, V
), а затем пытается найти строку, начинающуюся с case V:
. Если такая строка обнаружена, выполняются команды, расположенные сразу после нее (причем на все последующие операторы case что_то внимание не обращается, как будто их нет, а код после них остается без изменения). Если же найти такую строку не удалось, выполняются команды после default
(когда они заданы). Обратите внимание на операторы break
(которые условно заключены в квадратные скобки, чтобы подчеркнуть их необязательность), добавленные после каждой строки команд, кроме последней (для которой можно было бы тоже указать break
, что не имело бы смысла). Если бы не они, то при равенстве V=значение1
сработали бы не только команды1, но и все нижележащие.
Вот альтернативный синтаксис для конструкции switch-case
:
switch(выражение):
case значение1: команды1; [break;]
. . .
case значениеN: командыN; [break;]
[default: команды_по_умолчанию; [break]]
endswitch;
Инструкция require
Эта инструкция позволяет нам разбить текст программы на несколько файлов. Ее формат такой:
require имя_файла;
При запуске (именно при запуске, а не при исполнении!) программы интерпретатор просто заменит инструкцию на содержимое файла имя_файла (этот файл может так же содержать сценарий на PHP, обрамленный, как обычно, тэгами <?
и ?>
). Причем сделает он это только один раз (в отличие от include
, который рассматривается ниже): а именно, непосредственно перед запуском программы. Это бывает довольно удобно для включения в вывод сценария всяких "шапок" с HTML-кодом. Например:
Cоздаем файл 16.php
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
<title>Инструкция require</title>
</head>
<body bgcolor=yellow>
Cоздаем файл 17.php
Привет всем!
</body>
</html>
Cоздаем файл 18.php
<?php
require "16.php";
//. . . работает сценарий и выводит само тело документа
require "17.php";
?>
В окне веб-браузера это будет выглядеть ТАК.
Безусловно, это лучше, чем включать весь HTML-код в сам сценарий вместе с инструкциями программы. Вам скажет спасибо тот, кто будет пользоваться вашей программой и захочет изменить ее внешний вид. Однако, несмотря на кажущееся удобство, это все же плохая практика. Действительно, наш сценарий разрастается аж до трех файлов! А как было сказано выше, чем меньше файлов использует программа, тем легче с ней будет работать вашему дизайнеру и верстальщику (которые о PHP имеют слабое представление). О том, как же быть в этой ситуации, я расскажу позже в разделе, посвященной технике разделения кода и шаблонов.
Инструкция include
Эта инструкция практически идентична require
, за исключением того, что включаемый файл вставляется "в сердце" нашего сценария не перед его выполнением, а прямо во время. Какая разница? Поясню. Пусть у нас есть 10 текстовых файлов с именами 1.php, 2.php и так далее до 9.php, с различным содержимым: от Hello world! до Привет всем! и т.д.. Запустим такую программу:
<?php
for($i=1; $i<19; $i++) {
@include "$i.php";
}
?>
В результате мы получим вывод, состоящий из различных фалов. Из этого мы можем заключить, что каждый из наших файлов был включен по одному разу прямо во время выполнения цикла!
Давайте поэсперементируем. В корневой папке сайта достаточно различных файлов с обозначением .html. Давайте, используя цикл выведем несколько файлов данной категории в окно веб-браузера.
<?php
for($i=1; $i<2; $i++) {
include "$i.html";
}
?>
В окне веб-браузера это будет выглядеть ТАК.
Попробуйте теперь вместо include
подставить require
. Сравните результат.
<?php
for($i=1; $i<19; $i++) {
@require "$i.php";
}
?>
В окне веб-браузера это будет выглядеть ТАК.
Вы, должно быть, обратили внимание на, казалось бы, лишние фигурные скобки вокруг include
. Попробуйте их убрать. Вы тут же можете получить совершенно бестолковое сообщение об ошибке (или, еще хуже, программа начнет неправильно работать, а причину разыскать будет нелегко). Почему так происходит? Да потому, что include
не является на самом деле оператором в привычном нам смысле этого слова. Чтобы это понять, представьте, что каждый раз, когда интерпретатор встречает инструкцию include
, он просто "в лоб" заменяет ее на содержимое файла, указанного в параметре. А вдруг в этом файле несколько команд? Тогда в цикле выполнится только первая из них, а остальные будут запущены уже после окончания цикла. Так что общее правило гласит: всегда обрамляйте инструкцию include
фигурными скобками, если размещаете ее внутри какой-либо конструкции.
Трансляция и проблемы с include
Как мы знаем, перед исполнением PHP транслирует программу во внутреннее представление. Это означает, что в памяти создается как бы "полуфабрикат", из которого исключены все комментарии, лишние пробелы, некоторые имена переменных и т. д. Впоследствии это внутреннее представление интерпретируется (выполняется). Однако мы знаем также, что в программе могут встретиться такие места, "подводные камни" для интерпретатора, которые PHP не сможет оттранслировать заранее. В этом случае он их пропускает, "откладывает на потом", чтобы в момент, когда управление дойдет до определенной точки, опять запустить транслятор.
Одним из таких "камней" как раз и является инструкция include
. Как только управление программы доходит до нее, PHP вынужден приостановиться и ждать, пока транслятор не оттранслирует код включаемого файла. А это достаточно отрицательно сказывается на быстродействии программы, особенно большой. Поэтому, если вы пишете большой и сложный сценарий, применяйте инструкцию require
вместо include
, где только можно. В пользу последнего говорит также и перспектива появления в будущем компилятора для PHP, который будет уметь сохранять оттранслированный код в исполняемые файлы. Если вы будете использовать include
, то PHP никак не сможет определить во время компиляции, какие файлы вы собираетесь подключить в программе, поэтому в исполняемый файл их код не войдет. Что же оптимальнее — require
или include
? Если вы точно уверены, что определенный файл нужно присоединить ровно один раз и в точно определенное место, то воспользуйтесь require
. В противном случае более удачным выбором будет include
.
Комментарии(0)
Для добавления комментариев надо войти в систему и авторизоватьсяКомментирование статей доступно только для зарегистрированных пользователей:Зарегистрироваться