PHP-4 Эффективная работа


Константы
Переменные
Ссылки

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

Область видимости переменных представляет собой контекст, в рамках которого действительно ее определение. В большинстве случаев переменные РНР имеют одну область видимости. Кстати, это понятие распространяется на включаемые с помощью include и require файлы. Например:

$а = 1;
include "b.inc";

Здесь переменная $а доступна (видна) программному коду внутри файла b.inc. Однако внутри любой функции автоматически активизируется локальная область видимости: любая переменная, определенная внутри функции, ограничена ее пределами. Например:

$а = 1; // глобальная область видимости
Function Test () {
       echo $a; /* ссылка на локальную (!) переменную */
}
Test ();

Я не буду приводить снимок экрана с результатом работы этой программы по очень простой причине — вы все равно ничего не увидите! Функция echo пытается использовать значение локальной переменной $ а, которая не получила еще никакого значения.

внимание
       Это важное отличие РНР от Си и Perl, где по умолчанию используется глобальное определение переменных!

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

$а = 1; $Ь = 2;
Function Sum () {
          global $a, $b;
          $b = $а + $b; >
Sum ( );
echo $b;

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

Переменные с глобальной областью видимости могут быть считаны или установлены с помощью специального массива $GLOBALS. С его помощью мы можем переписать предыдущий пример вот так:

$а = 1;
$b = 2;

Function Sum () {
         $GLOBALS["b"] = $GLOBALS["a"] + SGLOBALS["b"];
}
Sum ();
echo $b;

Массив $GLOBALS представляет собой ассоциативный массив, в котором ключом является имя глобальной переменной, а содержимое этой переменной — значением элемента массива.

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

Function Test () {
       $а = 0;
       echo $a;
       $а++;
}

Как и следует ожидать, это определение функции совершенно бесполезно. Каждый ее вызов завершается одинаково: она выводит на экран 0, поскольку переменная $а всегда получает значение равное 0. Эта переменная создается при входе в функцию и уничтожается при ее завершении, поэтому инкрементирование переменной заканчивается пшиком: она уничтожается, а при очередном вызове функции создается заново. Чтобы реализовать подсчет количества вызовов функции Tes t ( ), можно либо использовать глобальную переменную, либо объявить переменную $а как статическую:

Function Test () {
          static $a = 0;
          echo $a;
          $а++;
}

Теперь все работает так, как мы и хотели: переменная инкрементируется при каждом обращении к функции Test ( ).

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

<?php
# /examples/php/part2/recursion.php
echo "<FONT SIZE=+1>";
Recursion( ) ;
Function Recursion () {
          static $count = 0;

          $count++;
          echo "Текущий уровень - <b>$count</b><br>";
          if ($count < 10) {
          /RecursionO ;
          }
          $count--;
}
?>

Результат ее работы приведен на рис. 4.3.

Рис. 4.3. Управление рекурсивными вызовами с помощью статической переменной

4.2.6. Полная неопределенность...

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

$а = "Всем";

А динамическая переменная будет использовать это значение в качестве имени переменной для дальнейшей работы. В нашем примере это переменная $Всем. Чтобы получить доступ к этой переменной, используйте вместо одного символа доллара два. Вот так:

$$а = "привет!";

Вы, наверное, еще не ощутили всего изящества этой конструкции. Теперь в РНР- машине определены две переменные: $а со значением Всем и переменная $Всем со значением привет!. Теперь оператор:

echo "$a ${$а}"; полностью эквивалентен конструкции: echo "$a $Всем"; которая выводит на экран строку «Всем привет!».

Чтобы использовать динамические переменные с массивами, вам необходимо предварительно решить проблему неоднозначности. Иначе говоря, если вы вводите $$а [ 1], анализатор должен понять, хотите ли вы использовать в качестве переменной $а[1] либо вначале использовать как переменную $$а, а уже затем использовать ее первый элемент (индекс [ 1]). Для решения проблемы неоднозначности используются фигурные скобки: в первом случае вы применяете запись ${$а[1]}, а во втором — ${$а} [1].

4.2.7. Переменные из внешнего мира

4.2.7.1. HTML-формы (GET и POST)

В тех случаях, когда PHP-программа вызывается как CGI-сценарий обработки экранной формы, все переменные этой формы автоматически становятся доступными PHP-программе. При этом, если при компиляции программы был включен параметр track_vars, эти переменные будут размещаться в ассоциативных массивах $HTTP_P05T_VARS, $HTTP_GET_VARS и/или $HTTP_P05T_FILES. Давайте рассмотрим небольшой пример. Предположим, что для ввода данных используется простая форма:

<form action="/php/part2/form-proc.php" method="post">
       Регистрационное имя: <input type="text" name="username"><br>
       <input type="submit">
</form>

После того как форма заполнена и нажата кнопка ввода, значение введенного текстового поля будет доступно как элемент ассоциативного массива $HTTP_POST_VARS ["username"].

Как и ранее, если при компиляции РНР была включена директива register_glo-bals, эта же переменная станет доступна как $username с глобальной областью видимости.

примечание
       Если вы корректно установили системную локаль, установили и правильно сконфигурирова- ли русский Apache, вы можете использовать и русскоязычные имена в переменных формы.

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

<form action="array-entry.php" method="post">
       Имя клиента: <input type="text" name="personal[name]"><br>
       Электронная почта: <input type="text" name="personal[emaiI]"><br>
       Предпочитаемый сорт пива: <br>
       <select multiple name="beer[]">
               <option vаluе="оболонь">0болонь
               <option vаluе="миллер">Миллер
               <option vаluе="балтика-3">Балтика №3
               </select>
       <input type="submit">
</form>

Но, пожалуй, и это не все. Иногда возникает необходимость во вводе многомерных массивов, например таблиц. В этом случае вы можете сразу же использовать в качестве имен полей указатели на массивы нужной размерности.

4.2.7.2. Обработка графической кнопки ввода формы

В примерах, рассмотренных выше, никаких особенных требований к кнопке ввода формы не предъявлялось. В самом деле — нажал и готово! Однако вы ведь можете использовать вместо стандартной кнопки какую-либо картинку, например вот так:

<input type=image
src="entry-gate.gif"    name="sub">

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

4.2.7.3. Плюшки HTTP

РНР прозрачным образом поддерживает работу с «плюшками» (cookies), впервые предложенными компанией Netscape. Плюшки предоставляют удобный механизм сохранения небольших структур данных на клиентских машинах и последующего их считывания сервером. Основное их назначение — идентификация пользователя и сохранение его пользовательских настроек. Для записи плюшек используется функция SetCookie( ) (см. раздел 15.2).

внимание
       Поскольку плюшки представляют собой разновидность заголовков HTTP, эта функция должна вызываться до того, как будет сгенерировано тело HTML-страницы.

Все плюшки, которые отправляются вам от клиента, автоматически преобразуются в переменные РНР точно так же, как и при обработке данных из методов GETи POST.

Если же вы хотите назначить одной плюшке несколько значений, то просто превратите ее в массив, добавив для этого к имени плюшки квадратные скобки ([ ]). Например, вот так:

SetCookie   ("MyCookie[]",   "Testing",   time()+3600);

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

$Count++;
SetCookie ("Count", $Count, time()+3600);
SetCookie ("Cart[$Count]", $item, time()+3600);

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

4.2.7.4. Переменные окружения

PHP-машина передает в ваше распоряжение переменные окружения точно так же, как и любые обычные РНР-переменные: echo $HOME; // Выводит содержимое переменной НОМЕ

Но поскольку информация пользователя, поступающая в программу посредством методов GET или POST, помещается тоже в обычные переменные РНР-машины, имеет смысл явно запрашивать переменную именно от окружения, чтобы быть уверенным в том, что вы считываете значение именно от окружения, а не от пользователя. Для этого вы должны использовать функцию getenv ().

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

4.2.7.5. Имена входных переменных форм

В большинстве случаев PHP-машина не изменяет имен переменных, которые передаются в программу. Однако поскольку точка не является разрешенным символом для переменной РНР, в этом случае приходится сделать исключение. Предположим, например, что вы столкнулись с оператором $varname. ext.

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

Чтобы избежать подобных коллизий, PHP-машина автоматически преобразует точки в именах внешних переменных в символы подчеркивания. Характерным примером может служить неявное преобразование переменных координат графической кнопки (см. 4.2.7.2) sub_x и sub_y в sub_x и sub_y соответственно.

4.2.8. Определение типов переменных

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

  • gettype();

  • is_long();

  • is_double();

  • is_string();

  • is_array();

  • is_object().

4.3. Ссылки

Ссылки в РНР представляют собой механизм, предназначенный для реализации синонимов, то есть для возможности обращения к одной и той же переменной с использованием различных имен. В отличие от указателей в языке Си в РНР этот механизм реализован на уровне системной таблицы символов примерно таким же образом, как и ссылки в файловой системе UNIX [2].

Ссылки позволяют двум или большему количеству переменных ссылаться на одно и то же фактическое содержимое (область памяти). Например при вводе оператора:
$а =& $b
переменные $а и $b будут указывать на одно и то же значение.

совет
       Обратите внимание, что $а и $b превращаются в полные синонимы друг друга. Речь не идет о том, $а указывает на $b или наоборот, а о том, что и $а, и $Ь указывают на одну и ту же область в памяти.

То же самое применимо и к функциям, которые возвращают ссылки на перемен- ные, и к оператору new.
$bar =& new fooclass9( );
$foo =& find_var ($bar) ;

До тех пор пока вы не используете приведенные выше конструкции, результат операции $ bar = new fooclass( ) не будет указывать на значение переменной $thi s конструктора. Это означает, что если вам необходимо использовать в конструкторе ссылку на $this, вы должны использовать присвоение со ссылкой, как показано выше. В противном случае вы будете иметь дело фактически с двумя различными объектами.

Вторая задача, реализуемая с помощью механизма ссылок, — это организация передачи данных по ссылке, а не по значению. Для ее решения, практически так же, как и в Perl [3], в теле функции создается локальная переменная и связывается по ссылке с переменной во «внешнем мире». На практике это выглядит вот так:

function foo (&$var) {
       $var++;
}
$a=5;
foo ($a);
В результате после завершения работы подпрограммы переменная $ а получит значение, равное 6.

4.3.1. Ограничения на применение ссылок

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

function foo (&$var) {
       $var =& $GLOBALS["baz"];
}
foo($bar) ;

В ходе выполнения вызова этой функции переменная $var в теле функции foo будет связана с переменной $Ьаr в главной программе. Но позже, в процессе выполнения foo, будет проведено переназначение ссылки на $GLOBALS [" baz" ]. И вы не можете никак добиться переназначения $ b а г за счет механизма ссылок, поскольку сама переменная $bаr внутри функции foo недоступна.

4.3.2. Передача значений по ссылке

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

function foo (&$var) { $var++;
}
       $a=5;
foo ($a);
// $a равно 6
Обратите внимание, что признак ссылочной операции помещается только в определении функции — сам вызов не претерпевает никаких изменений.

внимание
       В этом — важное отличие РНР от Си.

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

  • переменные, например foo($a);
  • оператор new, например foo (new foobar());
  • ссылки, возвращаемые из функции, например:
function &bar()
{
       $а = 5;
       return $a;
}
foo(bar()) ;

Все прочие структуры данных передаваться по ссылке не должны, поскольку результат такой операции не определен и может привести к забавным (а то и катастрофическим) казусам. Так, приведенный ниже пример передачи по ссылке попросту неработоспособен:

function bar() // Символ & отсутствует
{
       $а = 5;
       return $a;
}
foo(bar)) ;

foo($a = 5)    // Аргумент является выражением,
               // а не переменной
foo(5)    // Аргумент является константой,
               // а не переменной

4.3.3. Возвращение ссылок из функции

Возврат ссылки из функции оказывается полезным в тех случаях, когда вы хотите использовать функцию, чтобы отыскать, на какую переменную должна быть выполнена ссылка. В такой ситуации используется следующее решение: function &find_var ($param) {

       return $found_var;

$foo =& find_var ($bar);
$foo->x = 2;
В этом фрагменте устанавливается свойство объекта, возвращаемого функцией find_var,а не его копии, как это произошло бы без использования ссылки.

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

4.3.4. Отмена ссылочных связей

Если в ходе работы программы вам нужно разорвать ссылочную связь между двумя переменными, вам фактически требуется просто разорвать связь между именем одной из переменных и ее значением. При этом вам вовсе не требуется уничтожать содержимое переменной. Например в приведенном ниже фрагменте:
$а = 1;
$b =& $а;
unset ($a);
вы фактически «отмените» определение переменной $а, которое представляет собой запись в таблице символов. На старое значение этой переменной, которое также доступно через переменную $b, эта операция никак не повлияет.

совет
       Наиболее близким аналогом операции разыменования ссылки является команда (и системная функция) UNIX unlink.
назад
далее

Сайт управляется системой uCoz