PHP5_nachinayushim
.pdf284 Глава 6
Рис. 6.2.
Следующие три строки отображают значения глобальной, локальной и статиче+ ской переменных внутри функции:
echo "<br>содержимое глобального сообщения: " . $GLOBALS["global_message"]; echo "<br>содержимое локального сообщения: " . $local_message;
echo "<br>статическое число: " . $static_number;
Оператор return изменяет значение $static_number, увеличивая его на 1:
return $static_number = $static_number+1;
}
Программа начинает свою работу с вызова функции my_function():
echo "<b>Первый вызов функции:</b>"; my_function();
Отображаются значения глобальной, локальной и статической переменных, кото+ рые внутри функции равны "Глобальное сообщение", "Локальное сообщение" и 0.
Создание высококачественного кода 285
Как только функция заканчивает работу, выводится содержимое данных переменных вне функции. Здесь в зависимости от уровня отображения сообщений об ошибках возможно появление предупреждений о неопределенных переменных ++++++ это нор+ мально. Переменные $local_message и $static_number определены только внут+ ри кода функции, поэтому вне его они не существуют:
echo "<br><br><b>За пределами функции:</b>";
echo "<br>содержимое глобального сообщения: " . $global_message; echo "<br>содержимое локального сообщения: " . $local_message; echo "<br>статическое число " . $static_number;
Данная функция вызывается еще несколько раз, и каждый раз показывает значе+ ния своих внутренних переменных, а также значения переменных за ее пределами. Внутри функции изменяется только переменная $static_number.
Вложенность функций
Возможность создавать и вызывать функции внутри других функций называется вложенностью функций (nesting). Однако в большинстве обстоятельств вложенность функций не особенно полезна. Возможность вызова функций из других функций удобна, в книге уже приводились соответствующие примеры, и все же определение и вызов функции внутри другой функции может привести к возникновению проблем.
Например, можно написать родительскую функцию parent, внутри которой оп+ ределяется другая функция (назовем ее child). Проблема заключается в том, что если вызвать функцию parent дважды, то интерпретатор дважды попытается определить функцию child, а так как переопределять функции нельзя, сценарий аварийно за+ вершится. В большинстве случаев лучше определять функции отдельно.
Однако возможна другая ситуация (кроме использования функции переключения, которая рассматривалась выше), когда необходимо вызвать функцию из функции: ре+ курсия (функция вызывает сама себя).
Рекурсия
Вызов функции из самой себя называется рекурсией (recursion). Рекурсивный вызов функции создает циклические структуры, в которых функция продолжает вызывать себя до тех пор, пока удовлетворяется определенное условие. Однако условие необ+ ходимо явно создать внутри кода функции. Если нет уверенности, что существует ка+ кое+либо стоп+значение, которое так или иначе будет достигнуто, то рекурсия может длиться бесконечно. Рассмотрим небольшой пример.
Практика Рекурсивный вызов функции
1. Запустите редактор Web+страниц и введите следующий код:
<html>
<head></head>
<body>
<?php
if ($_POST['posted']) {
$num = $_POST['num']; function recursion($num) {
286 Глава 6
if ($num <= 1) { return 1;
} else {
return $num * recursion($num-1);
}
}
echo "Факториал " . $num . " равен " . (recursion($num));
}
?>
<form method="POST" action="recursion.php">
<input type="hidden" name="posted" value="true">
Найти факториал числа
<input name="num" type="text"> <br>
<br>
<input type="submit" value="Рассчитать факториал"> </form>
</body>
</html>
2.Сохраните файл как recursion.php и закройте его.
3.Откройте страницу recursion.php в браузере (рис. 6.3).
Рис. 6.3.
Теперь, если выбрать значение и нажать кнопку Рассчитать факториал, то добро+ совестный код с рекурсией выдаст ответ. Пример показан на рис. 6.4.
Создание высококачественного кода 287
Рис. 6.4.
Как это работает
Сначала объявляется рекурсивная функция, которой затем в качестве аргумента передается переменная $num_value:
<?php
if ($_POST['posted']) {
$num = $_POST['num']; function recursion($num) {
if ($num <= 1) { return 1;
} else {
return $num * recursion($num-1);
}
}
echo "Факториал " . $num . " равен " . (recursion($num));
}
?>
Затем необходимо убедиться, что значение $num больше единицы; если это не так, то возвращается 1 (факториал от 1, как известно, равен 1). Если введенное число больше единицы, то выполняется рекурсивная часть функции. В конце концов, выво+ дится результат.
В каждой итерации цикла значение не только умножается на последнее получен+ ное число (рекурсивная часть), но и постоянно уменьшается на единицу, чтобы га+ рантировать, что цикл, в конце концов, завершится. Этот сценарий не подходит для вычисления факториалов больших чисел, кроме того, он не работает с отрицатель+ ными числами, но в качестве примера его работы вполне достаточно.
288 Глава 6
Операторы include и require
Еще один способ облегчить использование и сопровождение кода заключается в подключении файлов (подключаемые файлы уже несколько раз использовались в при+ мерах кода). Подключать внешние файлы к текущему сценарию и запускать их очень легко. Все, что требуется сделать, это использовать конструкцию include или require (это именно языковые конструкции, а не функции, несмотря на то, что ино+ гда они называются функциями) с именем файла, который необходимо подключить. Единственное различие между двумя этими конструкциями заключается в том, как они обрабатывают неудачное подключение внешнего файла. Сбой include приводит к появлению предупреждения, а сбой require ++++++ к критической ошибке.
Можно отметить некоторые особенности работы данных конструкций.
Файл подключается путем вставки одной из этих конструкций в PHP+код, но синтаксический анализ основного файла в этой точке переходит из PHP+ режима в HTML+режим, поэтому чтобы запускать код подключаемого файла, этот код все равно необходимо помещать между соответствующими PHP+ разделителями.
С помощью одной из этих конструкций можно подключать файл изнутри какой+ либо функции, но в таком случае любые переменные, созданные в коде под+ ключаемого файла, будут иметь локальную по отношению к данной функции область действия.
PHP+сценарий внутри подключаемого файла выполняется при подключении. Любые PHP+переменные и их значения доступны в главном файле, как будто весь код подключаемого файла непосредственно вставлен в главный файл.
Рассмотрим несколько примеров использования данных конструкций в коде (можно использовать полные абсолютные или относительные пути):
include("filename") require ("filename");
Например, чтобы подключить с помощью include файл test.txt, необходимо использовать такой код:
include("test.txt");
Если файл test.txt содержит какой+либо текст, то этот текст будет включен в Web+страницу так, как если бы он был непосредственно записан в ее исходном коде.
Примечательно то, что в круглых скобках функций include или require можно также использовать имена переменных или присоединять переменные к имени файла с тем, чтобы сформировать имя существующего файла:
$Name ="1";
include ("test" . $Name . ".txt");
В результате этой конкатенации создается имя test1.txt, и если файл с таким име+ нем существует, значит он будет подключен, в противном случае генерируется ошибка.
Ниже перечислены ситуации, в которых подключаемые файлы удобны:
подключение текстового файла к странице;
определение переменных и/или констант, а также текста некоторых сообще+ ний об ошибках;
Создание высококачественного кода 289
вставка в страницу значений HTTP+переменных;
выполнение отдельного PHP+сценария (даже если он ничего не возвращает);
подключение часто используемых функций, которые нежелательно определять в каждой странице.
Подключаемые файлы удобны потому, что их можно непосредственно добавлять к файлу и в его коде определять необходимость подключения того или иного файла. Эта возможность рассматривается в следующем примере.
Практика Условное подключение
1. Запустите редактор Web+страниц и введите следующий текст:
Подключен первый файл
2.Сохраните созданный файл как file1.txt.
3.Закройте его, создайте новый текстовый файл и введите в него следующий текст:
Подключен второй файл
4.Сохраните данный файл как file2.txt.
5.Закройте данный файл, создайте новый и введите в него следующий код:
<html>
<head><title></title></head>
<body>
<?php
if (isset($_POST['posted'])) { $choice = $_POST['choice']; if ($choice <> "") {
include("file" . $choice . ".txt"); echo "<hr>";
}
}
?>
<form method="POST" action="include.php">
<input type="hidden" name="posted" value="true">
Выберите подключаемый файл? <select name="choice">
<option value="1">первый файл</option> <option value="2">второй файл</option> </select>
<br>
<br>
<input type="submit" value="Вывести текст"> </form>
</body>
</html>
6.Сохраните этот файл как include.php в том же каталоге, что и первые два текстовых файла.
7.Откройте в браузере страницу include.php и выберите файл из списка. На рис. 6.5 показан примерный результат.
290 Глава 6
Рис. 6.5.
Как это работает
Сначала выводится небольшая форма, предоставляющая пользователю выпадаю+ щий список (с именем choice) с двумя вариантами. Следующий PHP+код при выпол+ нении проверяет, какое значение было выбрано (если выбран, например, первый пункт, то значение равно 1) и использует это значение для формирования имени под+ ключаемого файла.
<?php
if (isset($_POST['posted'])) { $choice = $_POST['choice']; if ($choice <> "") {
include("file" . $choice . ".txt"); echo "<hr>";
}
}
?>
Естественно, должны существовать текстовые файлы file1.txt и file2.txt, содержащие какой+либо текст (в противном случае появится сообщение об ошибке).
О чем следует позаботиться при использовании подключаемых файлов
Многие Web+серверы не настроены на синтаксический анализ файлов с расшире+ нием .inc, поэтому лучше задавать для подключаемых файлов расширение .php ++++++
в таком случае никто не сможет просмотреть через Web+браузер содержимое этих
Создание высококачественного кода 291
файлов (возможно, секретное). Например, зная (или лишь догадываясь), что на сайте имеются .inc+файлы (возможно, содержащие секретную информацию, такую как па+ роли к базе данных), злоумышленник может просто ввести в своем браузере полный URL+указатель на такой файл и просмотреть его необработанный исходный код. Ре+ комендуется всегда задавать для подключаемых файлов расширение .php, тогда они безусловно будут обрабатываться PHP+интерпретатором.
Если требуется подключить один файл через другой подключаемый файл, например, через common.inc.php, который подключается вверху каждой страницы (это весьма распространенная Практика), но есть вероятность, что некоторые функции могут слу+ чайно определяться дважды, то следует использовать операторы include_once или require_once. Они работают так же, как include и require, но всегда подключают файл только однажды независимо от того, сколько раз файлы подключаются в коде.
Резюме
Функции представляют собой блоки кода, которые можно вызывать внутри про+ граммы. Они либо определены в PHP автоматически, как, например, функции обработ+ ки массивов sort() и ksort(), которые описывались в предыдущих главах, либо соз+ даются пользователями (пользовательские функции), как было показано в данной главе. Функции можно представить как небольшие ‘‘черные ящики’’, которые возвращают значение в ответ на переданные им соответствующие переменные. Переменные пере+ даются в функции через аргументы, определяемые в начале функции. Если переменные передаются не по ссылке, то значение, возвращаемое функцией, не влияет на перемен+ ные вне данной функции. Возвращаемое функцией значение можно использовать для переключения между различными блоками кода и выполнения различных действий.
В примерах данной главы было показано, что переменные ведут себя по+разному внутри функций. Эти различия вызваны областью видимости переменных. Перемен+ ные с локальной областью видимости существуют только во время работы функции и в конце ее работы уничтожаются, если они не были определены с использованием ключевого слова static. Переменные, определенные за пределами функций, внутри функций должны использоваться либо с ключевым словом global, либо через массив $_GLOBALS. В этой главе рассматривались подключаемые файлы, функции include(), require(), include_once() и require_once(), а также их использование для раз+ биения кода на модули.
Упражнение
Напишите функцию, с помощью которой пользователь сможет создать собствен+ ную Web+форму. В форме должны быть предусмотрены возможности выбора имен полей и типов полей, отправки информации в PHP+страницу и просмотра передан+ ных значений. Для выбора различных функций внутри главной функции необходимо использовать оператор switch..case.
7
Файлы и каталоги
Вряд ли пользователям хотелось бы посещать Web+сайты, код которых мог бы по+ лучить контроль над жестким диском пользовательского компьютера и делать все, что понадобилось разработчику сайта, например, записывать и стирать файлы и катало+ ги. По этой причине создатели языка JavaScript оставили эти возможности за рамками данного языка. PHP не имеет возможности записывать и стирать файлы с жесткого диска пользователя, но может создавать и удалять файлы и каталоги на Web+сервере. Это очень полезная возможность, потому что часто самый простой и наиболее эф+ фективный способ реализации в приложении определенной функциональности за+ ключается в использовании файловой системы сервера.
Файлы хранятся в каталогах на жестком диске, и поскольку в них информация со+ храняется после выключения или перезагрузки машины, они в отличие от временно+ го хранилища, такого как оперативная память, представляют собой постоянный меха+ низм хранения данных. Каталоги также являются файлами, но файлами особого типа, предназначенными для хранения других файлов. Каталоги создаются иерархически внутри других каталогов, начиная с корневого каталога.
Файлы могут содержать любые данные, а также информацию о самих себе, напри+ мер, имя владельца файла и дату создания. PHP облегчает работу с файловой систе+ мой, предоставляя ряд функций, которые позволяют получать информацию о файлах, открывать их, а также осуществлять считывание информации из файлов и запись в них. Эта глава посвящена PHP+функциям для работы с файловой системой. Здесь описываются PHP+функции чтения и записи файлов, открытие и закрытие файлов с помощью функций fopen() и fclose(), переименование и удаление файлов, нави+ гация в файлах и чтение каталогов. Кроме того, в данной главе рассматривается полу+ чение информации о правах доступа к файлам и пользователях файлов, а также реа+ лизация загрузки файлов на сервер через Web+интерфейс.
Существует множество различных типов файловых систем, хотя, возможно, поль+ зователям, привыкшим к Windows, не очень знакомы другие системы. Большинство Windows+систем предоставляют пользователю свободный доступ к файлам и каталогам,
Файлы и каталоги 293
тогда как Linux+системы обычно ограничивают доступ к файлам и каталогам путем обеспечения различных прав доступа для пользователей в системе. Работа файловой системы NTFS, которую можно использовать в Windows NT/2000 и более старших версиях, больше похожа на работу файловых систем в Linux+машинах ++++++ она также позволяет предоставлять разным пользователям различные права доступа.
Для PHP+разработчика весьма важно знать, используются ли в системе права дос+ тупа к файлам и как эти права устанавливаются, потому что некоторые функции тре+ буют установки определенных прав, прежде чем они смогут выполнить свою работу. К счастью, PHP предоставляет функции для проверки и установки прав доступа, а также для проверки привилегий текущего пользователя. PHP обычно запускается от имени того же пользователя, что и Apache (на Linux/Apache+серверах), или с привилегиями, предоставленными гостевой учетной записью в IIS+системах.
Обработка файлов и каталогов
Вся информация на жестком диске хранится в файлах того или иного типа, хотя большинство пользователей оперирует понятиями файлов и каталогов. Существуют обычные программные файлы, файлы данных, файлы, которые являются каталогами, и специальные файлы, которые позволяют жесткому диску отслеживать содержимое каталогов и файлов. В PHP имеются встроенные функции, которые способны обраба+ тывать любые существующие файлы, но чаще всего приходится работать с текстовы+ ми файлами, содержащими какие+либо данные.
Файл ++++++ не что иное, как упорядоченная последовательность байтов, хранящаяся на жестком диске, дискете, CD+ROM или другом носителе. Каталог представляет со+ бой специальный тип файла, в котором содержатся имена других файлов и каталогов (иногда называемых подкаталогами) и указатели на область их хранения на жестком диске. Для того чтобы манипулировать файлами, требуется знать, как сценарии под+ ключаются к файлам.
Между операционными системами Linux и Windows существует множество разли+ чий, например способ указания путей к каталогам. В Unix+подобных системах, таких как Linux, для разделения элементов пути используются символы косой черты, например:
/home/dan/data/data.txt
В Windows используются символы обратной косой черты:
C:\MyDocs\data\data.txt
К счастью, PHP в Windows в большинстве ситуаций автоматически конвертирует косую черту в обратную косую черту, например, код
$fp = fopen("/data/data.txt", "r");
не должен создавать каких+либо проблем на Windows+платформе. В некоторых случаях необходимо использовать путь непосредственно (например, когда загружен+ ный на сервер файл копируется из временного каталога в какой+либо другой каталог). В таких ситуациях использование обратной косой черты обязательно. Поскольку PHP интерпретирует обратную косую черту как escape+символ (экранирующий следующий за ним символ), путь необходимо задавать следующим образом:
"C:\\MyDocs\\data\\data.txt"
Позднее будет показан простой способ автоматического конвертирования косой черты в обратную косую черту.