Нетрадиционное использование do-while и break. Цикл foreach. Конструкция switch-case. Инструкция require. Инструкция include

Нетрадиционное использование 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оздаем файл 307.html

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
<title>Инструкция require</title>
</head>
<body bgcolor=yellow>

Cоздаем файл 308.html

Привет всем!
</body>
</html>

Cоздаем файл 40.php

<?php
require "307.html";
//. . . работает сценарий и выводит само тело документа
require "308.html";
?>

В окне веб-браузера это будет выглядеть ТАК.

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

Инструкция include

Эта инструкция практически идентична require, за исключением того, что включаемый файл вставляется "в сердце" нашего сценария не перед его выполнением, а прямо во время. Какая разница? Поясню. Пусть у нас есть 10 текстовых файлов с именами 1.php, 2.php и так далее до 9.php, с различным содержимым: от Hello world! до Привет всем! и т.д.. Запустим такую программу:

<?php
for($i=1; $i<10; $i++) {
include "$i.php";
}
?>

В окне веб-браузера это будет выглядеть ТАК.

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

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

<?php
for($i=22; $i<36; $i++) {
include "$i.html";
}
?>

В окне веб-браузера это будет выглядеть ТАК.

В результате получен вывод из 13 файлов.

Попробуйте теперь вместо include подставить require. Сравните результат.

<?php
for($i=1; $i<10; $i++) {
require "$i.php";
}
?>

В окне веб-браузера это будет выглядеть ТАК.

Вы, должно быть, обратили внимание на, казалось бы, лишние фигурные скобки вокруг include. Попробуйте их убрать. Вы тут же можете получить совершенно бестолковое сообщение об ошибке (или, еще хуже, программа начнет неправильно работать, а причину разыскать будет нелегко). Почему так происходит? Да потому, что include не является на самом деле оператором в привычном нам смысле этого слова. Чтобы это понять, представьте, что каждый раз, когда интерпретатор встречает инструкцию include, он просто "в лоб" заменяет ее на содержимое файла, указанного в параметре. А вдруг в этом файле несколько команд? Тогда в цикле выполнится только первая из них, а остальные будут запущены уже после окончания цикла. Так что общее правило гласит: всегда обрамляйте инструкцию include фигурными скобками, если размещаете ее внутри какой-либо конструкции.

Трансляция и проблемы с include

Как мы знаем, перед исполнением PHP транслирует программу во внутреннее представление. Это означает, что в памяти создается как бы "полуфабрикат", из которого исключены все комментарии, лишние пробелы, некоторые имена переменных и т. д. Впоследствии это внутреннее представление интерпретируется (выполняется). Однако мы знаем также, что в программе могут встретиться такие места, "подводные камни" для интерпретатора, которые PHP не сможет оттранслировать заранее. В этом случае он их пропускает, "откладывает на потом", чтобы в момент, когда управление дойдет до определенной точки, опять запустить транслятор.

Одним из таких "камней" как раз и является инструкция include. Как только управление программы доходит до нее, PHP вынужден приостановиться и ждать, пока транслятор не оттранслирует код включаемого файла. А это достаточно отрицательно сказывается на быстродействии программы, особенно большой. Поэтому, если вы пишете большой и сложный сценарий, применяйте инструкцию require вместо include, где только можно. В пользу последнего говорит также и перспектива появления в будущем компилятора для PHP, который будет уметь сохранять оттранслированный код в исполняемые файлы. Если вы будете использовать include, то PHP никак не сможет определить во время компиляции, какие файлы вы собираетесь подключить в программе, поэтому в исполняемый файл их код не войдет. Что же оптимальнее — require или include? Если вы точно уверены, что определенный файл нужно присоединить ровно один раз и в точно определенное место, то воспользуйтесь require. В противном случае более удачным выбором будет include.

назадвверхвперед
Rambler's Top100