Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

web - tec / PHP 5 для начинающи

.pdf
Скачиваний:
72
Добавлен:
12.06.2015
Размер:
26.79 Mб
Скачать

Создание высококачественного кода 273

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

function bonus($total_sales, $bonus_factor)

{

$bonus = $total_sales * $bonus_factor; return $bonus;

}

Теперь, чтобы вызывать модифицированную функцию расчета премии, необхо+ димо передать ей два значения: total_sales и bonus_factor.

$total_sales = 120000; $bonus_factor = 0.15;

echo (bonus($total_sales, $bonus_factor));

Функции можно определять в любом месте PHP+программы. Обычно функции оп+ ределяют в отдельном файле и просто подключают его (с помощью функций include или require) в начале главного файла сценария. Определять или инициализировать переменные перед тем, как определяется функция, необязательно; однако необходимо убедиться, что они определены или проинициализированы перед вызовом функции.

Например, следующий код работает:

<?php

$total_sales = 190999; // здесь начинается выполнение

$bonus_factor = 0.15;

echo (bonus($total_sales, $bonus_factor)); // здесь функция вызывается function bonus($total_sales, $bonus_factor) // здесь функция определяется {

$bonus = $total_sales * $bonus_factor; return $bonus;

}

?>

Но и представленный ниже код работает также хорошо:

<?php

function bonus($total_sales, $bonus_factor) // здесь функция определяется { $bonus = $total_sales * $bonus_factor;

return $bonus;

}

$total_sales = 190999; // здесь начинается выполнение

$bonus_factor = 0.15;

echo (bonus($total_sales, $bonus_factor)); // здесь функция вызывается ?>

Необходимо сделать важное замечание о работе функций. Чтобы передавать значения в функцию, можно использовать любые имена переменных. Например, предположим, что вместо использования одних и тех же имен ($total_sales и $bonus_factor) как вне, так и внутри функции, используются имена $out_total_sales и $out_bonus_factor для переменных, существующих за пределами функции, а внутри функции использу+ ются имена $in_total_sales и $in_bonus_factor. Такой код работал бы, и выгля+ дел бы он следующим образом:

<?php

function bonus($in_total_sales, $in_bonus_factor) // здесь функция определяется { $bonus = $in_total_sales * $in_bonus_factor;

return $bonus;

}

$out_total_sales = 190999; // здесь начинается выполнение

$out_bonus_factor = 0.15;

echo (bonus($out_total_sales, $out_bonus_factor)); // здесь функция вызывается ?>

274 Глава 6

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

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

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

имена пользовательским функциям задает разработчик:

функции могут принимать параметры, которые являются значениями или пе+ ременными, определенными в скобках после имени функции;

параметры отделяются друг от друга запятыми;

код функции записывается в фигурных скобках после имени функции и параметров;

внутри функции необходимо использовать ключевое слово return для возвра+ щения значения, которое можно использовать за пределами функции;

если значение возвращать не требуется, то ключевое слово return обозначает конец кода функции;

функции не выполняются до тех пор, пока они не вызваны в какой+либо строке PHP+сценария;

вызывать функцию можно как до, так и после ее объявления в коде ++++++ место+ расположение определения функции не имеет значения;

вызывать функцию можно столько раз, сколько необходимо, и передавать в функцию любые значения, отправляя их как постоянные значения или как значения внутри каких+либо переменных.

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

Рассмотрим пример кода holiday.php из главы 4 и напишем функцию для вычис+ ления стоимости недельного отдыха.

Практика Использование простой функции

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

<html>

<head><title></title></head>

<body>

<b>Бронирование гостиниц Namllu</b> <?php

Создание высококачественного кода 275

function calculator($price, $city_modifier, $star_modifier)

{

return $price = $price * $city_modifier * $star_modifier;

}

if (isset($_POST['posted'])) { $price = 500; $star_modifier = 1; $city_modifier = 1;

$destgrade = $_POST['destination'].$_POST['grade']; switch($destgrade) {

case "Barcelonathree"; $city_modifier = 2; break;

case "Barcelonafour"; $city_modifier = 2; $star_modifier = 2; break;

case "Viennathree"; $city_modifier = 3.5; break;

case "Viennafour"; $city_modifier = 3.5; $star_modifier = 2; break;

case "Praguethree"; break;

case "Ppraguefour"; $star_modifier = 2; break;

default;

$city_modifier = 0;

echo ("Пожалуйста, вернитесь и начните сначала"); break;

}

if ($city_modifier <> 0)

{

echo "Недельная стоимость проживания в $_POST[destination] - " . "$" . calculator($price, $city_modifier, $star_modifier);

}

}

?>

<form method="POST" action="holiday3.php">

<input type="hidden" name="posted" value="true">

Где Вы хотели бы провести отпуск? <br>

<br>

<input name="destination" type="radio" value="Prague">

Прага

<br>

<input name="destination" type="radio" value="Barcelona">

Барселона

<br>

<input name="destination" type="radio" value="Vienna">

Вена

<br>

<br>

В гостинице какого класса Вы хотели бы остановиться? <br>

<br>

<input name="grade" type="radio" value="three">

Трехзвездочная

<br>

<input name="grade" type="radio" value="four">

Четырехзвездочная

276 Глава 6

<br>

<br>

<input type="submit" value="Отправить запрос"> </form>

</body>

</html>

2.Сохраните и закройте файл.

3.Откройте страницу holiday3.php (рис. 6.1) в браузере, сделайте выбор и на+ жмите кнопку Отправить запрос.

Рис. 6.1.

Как это работает

Данная форма аналогична форме в главе 4 ++++++ она принимает от пользователя два значения и передает их посредством $_POST+переменных ($_POST[destination] и $_POST[grade]) PHP+сценарию. PHP+код начинается с определения функции (calculator) для вычисления стоимости отпуска:

function calculator($price, $city_modifier, $star_modifier)

{

return $price = $price * $city_modifier * $star_modifier;

}

Создание высококачественного кода 277

Пользовательская функция calculator() принимает три параметра: базовую стоимость отдыха, коэффициент наценки для выбранного города и коэффициент для класса гостиницы. Затем функция перемножает эти переменные и возвращает значе+ ние ($price) ++++++ окончательную стоимость отдыха в гостинице.

Остальная часть программы работает так же, как и раньше, объединяя пункт назна+ чения и класс гостиницы в одно значение, которое используется для выбора различных вариантов. Есть, однако, одно небольшое изменение в case+блоке по умолчанию: пере+ менной $city_modifier присваивается значение 0, если ни один из вариантов не вы+ бран. Перед вызовом функции calculator() выполняется проверка данной перемен+ ной. Если ее значение не равно нулю, то функцию можно вызывать внутри оператора echo(), добавляя к результату функции текст с помощью оператора конкатенации (.):

if ($city_modifier <> 0)

{

echo "Недельная стоимость проживания в $_POST[destination] - " . "$" . calculator($price, $city_modifier, $star_modifier);

}

Функции переключения

Можно написать функцию, которая бы принимала входящие значения и на осно+ вании этих значений выбирала бы другие функции для обработки данных, так же, как это делается в PHP+программе с помощью структуры switch. Это весьма эффектив+ ная особенность пользовательских функций в PHP.

Рассмотрим небольшой пример. Предположим, что необходимо создать приложе+ ние, которое выбирает записи из различных таблиц базы данных. С помощью пере+ менной $table_name в функцию переключения можно передать какое+либо входное значение, а функция на основании этого значения примет решение, какую функцию с SQL+запросом необходимо выполнить:

function query_switch($table_name) { switch ($table_name){

case "clients":

$query = query__clients_gen()); break;

case "orders":

$query = query_orders_gen()); break;

case "employees":

$query = query_employees_gen()); break;

default:

echo "Выберите имя таблицы";

}

}

function query_client_gen()

{

//формирование запроса к базе данных для выбора записей из

//таблицы clients

}

function query_orders_gen()

{

//формирование запроса к базе данных для выбора записей из

//таблицы orders

}

function query_employees_gen()

278 Глава 6

{

//формирование запроса к базе данных для выбора записей из

//таблицы employees

}

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

Поскольку результат функции (которая возвращает значение) можно непосредст+ венно присвоить переменной, этот результат можно использовать в операторе switch..case. Например, предположим, что требуется создать небольшую управляю+ щую функцию, которая показывает количество посещений определенной страницы. Количество посещений, возвращаемое функцией, можно использовать в операторе echo и вывести пользователю понятное сообщение, как показано в следующем примере:

switch ($hit_counter = get_hits($current_page)){

case $hit_counter <100:

echo "Сегодня мало посещений"; break;

case $hit_counter <1000:

echo "Сегодня много посещений"; break;

case $hit_counter <10000:

echo "Сегодня очень много посещений"; break;

}

В переменной $hit_counter можно хранить любое значение, возвращаемое функцией get_hits($current_page) (в которой переменной $current_page при+ своено имя файла текущей страницы и которая получает от какого+либо сценария об+ щее число посещений за текущий день). Можно присваивать значение переменной $hit_counter непосредственно в скобках оператора switch().

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

Как значения попадают в функции

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

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

Создание высококачественного кода 279

Передача по значению

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

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

function bonus($total_sales) { $bonus = $total_sales * 0.15; return $bonus;

}

$total_sales = 120499;

echo "Сумма премии " . bonus($total_sales); echo "Общий объем продаж " . $total_sales;

echo "Общий объем продаж равен \$120 499, а сумма премии равна " . bonus(120499);

Следует отметить, что даже после того, как значение $total_sales было уста+ новлено за пределами функции, а затем было передано ей для обработки, внешнее значение переменной $total_sales не изменилось.

Передача по ссылке

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

Как это реализовать в коде? В определении функции перед именем аргумента, пе+ редаваемого по ссылке, необходимо поставить амперсанд (&). В приведенном ниже примере показана передача аргумента $salary.

Предположим, что премия прибавляется к значению переменной $salary. Оче+ видно, это можно было бы сделать за пределами функции, но проще и понятнее сде+ лать это внутри функции. Рассмотрим следующий код:

function bonus($total_sales,&$salary)

{

$bonus = $total_sales * 0.15; $salary = $salary + $bonus; return $salary;

}

$total_sales = 120499; $salary = 40000;

bonus($total_sales,$salary);

echo "Ваша заработная плата, включая премию равна " . $salary; echo "Объем продаж равен " . $total_sales;

В данном случае нет необходимости присваивать какой+либо переменной результи+ рующее значение, возвращаемое функцией bonus(); переменной $salary присваива+ ется значение 40000, а затем переменная передается по ссылке в функцию bonus(), и, когда функция завершает свою работу, она возвращает значение непосредственно в переменную $salary. Очень лаконично.

280 Глава 6

Установка значений по умолчанию

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

Однако есть одна особенность: необходимо определять все аргументы со значе+ ниями по умолчанию справа от аргументов, не имеющих стандартных значений. Эта особенность не очень заметна, но если ее проигнорировать, то написанная функция будет работать не так, как должна. В следующем примере определяется функция для расчета премии. Значение по умолчанию для зарплаты ($40 000) устанавливается справа от аргумента total_sales:

function bonus($total_sales,&$salary = 40000)

{

$bonus = $total_sales * 0.15; $salary = $salary + $bonus; return $salary;

}

$total_sales = 120499;

bonus($total_sales);

echo "Ваша зарплата, включая премию, равна " . $salary; echo "Ваш общий объем продаж равен " . $total_sales;

Это означает, что если при вызове функции ей не было передано какое+либо дру+ гое значение для аргумента $salary, то функция автоматически будет выполнять вы+ числения для значения 40000. Однако если какое+либо значение было передано функ+ ции (неважно какое: больше, меньше или равное 40000), то функция для вычислений будет использовать именно переданное значение.

Важность порядка аргументов

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

Область видимости переменных

Продолжим начатое в главе 2 обсуждение темы области видимости переменных. В PHP+сценарии можно создавать переменные как внешние (вне функции), так и внут+ ренние (внутри функции) по отношению к функции. Если переменная $total_sales создается за пределами кода функции, а затем ее значение передается в функцию, ко+ торая обрабатывает свою внутреннюю переменную с таким же именем, то в сценарии будет две разные переменные с именем $total_sales. Очевидно, такой сценарий будет работать правильно, только если переменные не будут влиять друг на друга. Поэтому

Создание высококачественного кода 281

PHP (как и многие другие языки программирования) использует понятие области ви+ димости и различает подобные переменные.

Можно представить себе множество ситуаций, когда удобно использовать в одном сценарии несколько переменных с одинаковыми именами. Область видимости позволя+ ет PHP обрабатывать две переменные с одним и тем же именем, пока они остаются в со+ ответствующих блоках кода. (Во многом таким же образом пространства имен позволя+ ют работать XML+элементам с одинаковыми именами внутри одного XML+документа и оставаться при этом разделенными. Пространства имен XML рассматриваются в главе 8.)

Кроме области видимости, созданные в PHP+сценарии переменные также имеют время жизни. Переменная, созданная внутри функции, существует только до тех пор, пока функция не закончит свою работу. Если эта переменная не определена как ста* тическая (подробнее статические переменные рассматриваются в этой главе далее), то по окончании работы функции переменная теряется. Таким образом, областью ви+ димости переменной в данном случае является функция, а время жизни переменной равно времени работы функции (каждый раз при вызове функции создается новая внутренняя переменная и она имеет новое время жизни). Все переменные в PHP+ сценарии уничтожаются, когда сценарий завершает свою работу.

Глобальные и локальные переменные

Переменные, созданные вне функций, существуют до конца работы сценария и, следо+ вательно, имеют глобальную область видимости, т.е. доступны из любой точки сценария. Однако чтобы получить к ним доступ из какой+либо функции, необходимо использовать ключевое слово global. Наличие ключевого слова global перед именем переменной означает, что переменную можно использовать внутри функции (но создать другую пе+ ременную с тем же именем нельзя, потому что это имя принято также внутри функции). Переменные, созданные внутри функции, имеют локальную область видимости.

Рассмотрим пример работы локальных и глобальных переменных:

<?php

$global_message = "Глобальное сообщение"; function addto_message($global_message)

{

global $global_message; $global_message .= " и немного больше";

return $global_message; }

addto_message($global_message);

echo "Глобальное сообщение – это " . $global_message; ?>

Код выводит на экран предложение: ‘‘Глобальное сообщение ++++++ это Глобальное сообщение и немного больше’’, так как вызываемая функция изменяет значение пе+ ременной $global_message. Это происходит потому, что используется ключевое слово global; изменение переменной таким способом очень похоже на передачу ар+ гумента в функцию по значению.

Фактически использование ключевого слова global перед именем переменной внутри функции создает ссылку на суперглобальный массив с именем $_GLOBALS. В данном случае создание переменной $global_message (или любой другой перемен+ ной в данном контексте) за пределами функции (и, следовательно, с глобальной обла+ стью видимости) автоматически делает ее частью массива $_GLOBALS. Итак, можно выделить два способа доступа к глобальным переменным внутри функций: использо+ вание ключевого слова global (например, так: global $global_message) и ис+ пользование суперглобального массива ($_GLOBALS $_GLOBALS[global_message]).

282 Глава 6

Создание статических переменных в функциях

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

Предположим, например, что необходимо каждый раз подсчитывать извлекаемые из базы данных записи. Для этого можно использовать такой код:

<?php

function get_records($table)

{

//подключение к базе данных //извлечение записей

//get_record_count

static $record_count;

//присвоить $record_count количество возвращенных записей //плюс текущее значение данной переменной

echo "текущее количество выбранных записей равно " . $record_count; //вернуть какое-либо значение

}

Хотя представленный пример почти полностью состоит из псевдокода, он показы+ вает, как создавать статическую переменную $record_count. Должно быть очевидно, что при каждом вызове данной функции (по крайней мере, в пределах выполнения од+ ного PHP+сценария) значение переменной $record_count будет увеличиваться на ко+ личество выбранных записей. Например, если в пределах одного PHP+сценария в пер+ вый раз было выбрано 20 записей, во второй 30, а в последний раз 40, то переменной $record_count будет присвоено значение 90. Естественно, можно каждый раз выво+ дить текущее количество записей, что и делается в данном примере.

Обобщим знания о глобальных, локальных и статических переменных:

глобальные переменные существуют на протяжении работы всей программы, но чтобы их использовать внутри функции, необходимо предварять их имена ключевым словом global или обращаться к ним посредством суперглобально+ го массива $_GLOBALS;

локальные переменные содержат значения, которые существуют только внутри функции и только во время ее работы;

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

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

Практика Демонстрация области видимости

1. Откройте редактор Web+страниц и введите следующий код:

<html>

<head><title></title></head>

<body>

Соседние файлы в папке web - tec