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

Последнее обновление: 1.11.2015

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

Локальные переменные

Локальные переменные создаются внутри функции. К таким переменным можно обратиться только изнутри данной функции. Например:

В данном случае в функции get() определена локальная переменная $result . И из общего контекста мы не можем к ней обратиться, то есть написать $a = $result; нельзя, так как область действия переменной $result ограничено функцией get() . Вне этой функции переменной $result не существует.

То же самое относится и к параметрам функции: вне функции параметры $lowlimit и $highlimit также не существуют.

Как правило, локальные переменные хранят какие-то промежуточные результаты вычислений, как и в примере выше.

Статические переменные

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

Чтобы указать, что переменная будет статической, к ней добавляется ключевое слово static . При трех последовательных вызовах функции getCounter() переменная $counter будет увеличиваться на единицу.

Если бы переменная $counter была обычной нестатической, то при каждом вызове функция getCounter() выводила бы 1.

Как правило, статические переменные служат для создания различных счетчиков, как в примере выше.

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

Иногда требуется, чтобы переменная была доступна везде, глобально. Подобные переменные могут хранить какие-то общие для всей программы данные. Для определения глобальных переменных используется ключевое слово global :1

"; } getGlobal(); echo $gvar; ?>

После вызова функции getGlobal() к переменной $gvar можно будет обратиться из любой части программы.

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

В этом примере переменная $a будет доступна также внутри включенного скрипта - main.inc .

Локальные переменные

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

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

30 ?>

В результате исполнения этого фрагмента будет выведено: 30.

Внутри функции birth() выполняется присваивание переменной $age значения 1, но это не таже самая переменная, что была определена в глобальной области видимости. Поэтому, когда выполняется вывод на экран значения переменной $age , выводится первоначальное значение 30. Стоит отметить, что локальные переменные создаются в момент вызова функции и удаляются после окончания работы функции.

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

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

Наиболее правильный подход заключался бы в том, чтобы поместить набор операций в виде функций/класса с собственным именем в файл, подключить файл (без какого-либо оператора возврата за пределами функций), а затем вызывать функцию явно с требуемым набором аргументов.

Так в чем проблема-то?

Все предельно просто, вы делаете include внутри метода method , а значит переменные указанные в подключаемом файле инициализируются в области видимости метода method . Следовательно, переменная $lang не является глобальной, а ограничена видимостью метода , а вы обращаетесь к глобальной переменной, поэтому при использовании модификатора global она будет равна null.

Если делать include в глобальной области видимости, тогда переменная lang станет общедоступной (global) и ее использование станет возможным. Это легко проверить, достаточно в подключаемом файле перед началом определения какой-либо переменной написать global $переменная.

Пример:

include "file1.php"; function include2() { include "file2.php"; }
  • file1.php определен в глобальной области видимости.
  • file2.php определен в локальной области видимости функции include2.

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

А почему подход с глобальными переменными плохой?

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

Предположим, у вас есть функция, результат которой зависит от глобальной переменной. Вы вызываете её, вызываете - но через 10 минут функция начинает возвращать неверные результаты. Что случилось? Ведь на вход вы передаёте ей всё тот же набор параметров? Гм, кто-то поменял значение глобальной переменной... Кто это мог быть? Да кто угодно - ведь глобальная переменная доступна всем..

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

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

Знаете какой наилучший префикс для глобальных переменных?

Область видимости переменной - это контекст, в котором эта переменная определена. В большинстве случаев все переменные PHP имеют только одну область видимости. Эта единая область видимости охватывает также включаемые (include) и требуемые (require) файлы. Например:

$a = 1 ;
include "b.inc" ;
?>

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

$a = 1 ; /* глобальная область видимости */

Function test ()
{
echo $a ; /* ссылка на переменную локальной области видимости */
}

Test ();
?>

Этот скрипт не сгенерирует никакого вывода, поскольку выражение echo указывает на локальную версию переменной $a , а в пределах этой области видимости ей не было присвоено значение. Возможно вы заметили, что это немного отличается от языка C в том, что глобальные переменные в C автоматически доступны функциям, если только они не были перезаписаны локальным определением. Это может вызвать некоторые проблемы, поскольку люди могут нечаянно изменить глобальную переменную. В PHP, если глобальная переменная будет использоваться внутри функции, она должна быть объявлена глобальной внутри определения функции.

Ключевое слово global

Сначала пример использования global :

Пример #1 Использование global

$a = 1 ;
$b = 2 ;

function Sum ()
{
global $a , $b ;

$b = $a + $b ;
}

Sum ();
echo $b ;
?>

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

Второй способ доступа к переменным глобальной области видимости - использование специального, определяемого PHP массива $GLOBALS . Предыдущий пример может быть переписан так:

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

Пример #3 Суперглобальные переменные и область видимости

function test_global ()
{
// Большинство предопределенных переменных не являются
// "супер", и чтобы быть доступными в локальной области
// видимости, функции требуют указания "global".
global $HTTP_POST_VARS ;

Echo $HTTP_POST_VARS [ "name" ];

// Суперглобальные переменные доступны в любой области
// видимости и не требуют указания "global".
// Суперглобальные переменные доступны, начиная с PHP 4.1.0, а
// использование HTTP_POST_VARS считается устаревшим.
echo $_POST [ "name" ];
}
?>

Замечание :

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

Использование статических (static ) переменных

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

Пример #4 Демонстрация необходимости статических переменных

function test ()
{
$a = 0 ;
echo $a ;
$a ++;
}
?>

Эта функция довольно бесполезна, поскольку при каждом вызове она устанавливает $a в 0 и выводит 0 . Инкремент переменной $a ++ здесь не играет роли, так как при выходе из функции переменная $a исчезает. Чтобы написать полезную считающую функцию, которая не будет терять текущего значения счетчика, переменная $a объявляется как static:

Пример #5 Пример использования статических переменных

function test ()
{
static $a = 0 ;
echo $a ;
$a ++;
}
?>

Теперь $a будет проинициализирована только при первом вызове функции, а каждый вызов функции test() будет выводить значение $a и инкрементировать его.

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

Замечание :

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

Пример #7 Объявление статических переменных

function foo (){
static $int = 0 ; // верно
static $int = 1 + 2 ; // неверно (поскольку это выражение)
static $int = sqrt (121 ); // неверно (поскольку это тоже выражение)

$int ++;
echo $int ;
}
?>

Замечание :

Статические объявления вычисляются во время компиляции скрипта.

Ссылки с глобальными (global ) и статическими (static ) переменными

Движок Zend Engine 1, лежащий в основе PHP 4, оперирует модификаторами переменных static и global как ссылками . Например, реальная глобальная переменная, внедренная в область видимости функции указанием ключевого слова global , в действительности создает ссылку на глобальную переменную. Это может привести к неожиданному поведению, как это показано в следующем примере:

function test_global_ref () {
global $obj ;
$obj = &new stdclass ;
}

function test_global_noref () {
global $obj ;
$obj = new stdclass ;
}

Test_global_ref ();
var_dump ($obj );
test_global_noref ();
var_dump ($obj );
?>

Результат выполнения данного примера:get_instance_noref () {
static $obj ;

Echo "Статический объект: " ;
var_dump ($obj );
if (!isset($obj )) {
// Присвоить объект статической переменной
$obj = new stdclass ;
}
$obj -> property ++;
return $obj ;
}

$obj1 = get_instance_ref ();
$still_obj1 = get_instance_ref ();
echo "\n" ;
$obj2 = get_instance_noref ();
$still_obj2 = get_instance_noref ();
?>

Результат выполнения данного примера:

Статический объект: NULL
Статический объект: NULL

Статический объект: NULL
Статический объект: object(stdClass)(1) {
["property"]=>
int(1)
}

Этот пример демонстрирует, что при присвоении ссылки статической переменной она не запоминается , когда вы вызываете функцию &get_instance_ref() во второй раз.

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

Область видимости

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

По умолчанию они ограничены локальной областью видимости функции. А как сделать, чтобы переменную видели файлы за её границами, причем могли бы ещё и использовать? Для этого и предусмотрена в PHP глобальная переменна.

Ключевое слово "global"

А вот как объявить глобальную переменную PHP? В достижении этой цели нам поможет слово "global". Размещать его необходимо перед переменной, которую необходимо сделать глобальной (наример, global «Переменная»).

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

Почему такая странная формулировка? Дело в том, что одновременно с этим могут существовать и локальные версии. Но доступными они будут исключительно в тех файлах, где объявлены. А для всех остальных будут действовать глобальные переменные класса PHP. Поэтому необходимо быть осторожным. И чтобы не было сомнений, вот вам пример, как они выглядят: global a.

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

Другой вариант записи

Можно ли в PHP создать глобальную переменную другим способом? Да, и даже не одним. Для начала давайте рассмотрим $GLOBALS. Это ассоциативный в нём - это имя. В качестве значения выступает содержимое глобальной переменной. Следует отметить, что данный массив после объявления существует в любой области видимости. Это даёт основания считать его суперглобальным. Выглядит он таким образом: $GLOBALS["Переменная"] .

Предопределённые/суперглобальные переменные

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

В этом языке программирования имеются свои особенности. Так, важным является то, что предопределённые переменные здесь не имеют установки «супер», то есть они доступны не во всех местах. Как же это исправить? Чтобы предопределённая переменная была доступна в какой-то локальной области, её необходимо объявлять следующим образом: global «Переменная». Вроде бы то же, что и ранее рассказывалось, верно? Верно, да не совсем. Давайте рассмотрим уже «боевой» пример:

  • global $HTTP_POST_VARS;
  • echo $HTTP_POST_VARS["name"].

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

Ссылки и безопасность

Как видите, в PHP создать глобальную переменную не проблема. А вот есть ли какие-то особенности относительно ссылок? Да, может быть неожиданное поведение при использовании global. Но перед этим небольшая предыстория.

В версии 4.2.0 директива register_globals по умолчанию изменилась с включенного состояния на выключенное. Для большинства пользователей это не очень важно, а зря. Ведь это напрямую сказывается на безопасности разрабатываемого продукта. Если вам необходимо сделать переменную глобальной, PHP-директива на этот параметр непосредственно не повлияет. Но некорректное использование уже может создать прецеденты безопасности.

Так, если register_globals находится во включенном состоянии, то перед исполнением написанного кода инициализируются различные переменные, которые необходимы, например, чтобы отправлять HTML-формы. Поэтому и было принято решение отключить её.

Почему состоянием данной директивы в php глобальная переменная обязана многим? Дело в том, что при включенном состоянии разработчики не всегда с уверенность могли сами себе ответить на вопрос, откуда она пришла. С одной стороны, это облегчало написание кода. Но с другой - это создавало угрозу безопасности. Поэтому, чтобы избежать ошибок, а также перемешивания данных и была отключена директива.

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

Опасный код

Давайте установим, что переменная является истинной для тех, кто прошел авторизацию:

if (authenticate_user()) {
$authorize = true;
}

if ($authorize) {
include "/highly/sensitive/data.php";
}

В данном состоянии переменная может устанавливаться автоматически. Учитывая, что данные могут быть попросту заменены, и источник их происхождения не устанавливается, то любой человек может пройти такую проверку и выдать себя за кого-то другого. При желании, злоумышленником (или просто любопытным, но неопытным человеком) может быть нарушена логика работы скрипта.

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

Надёжный вариант кода

Для достижения этой цели можно или выключить работу директивы, или прописать более сложный код. Например, вот такой:

if (isset($_SESSION["username"])) {

Echo "Привет {$_SESSION["username"]}";

Echo "Привет Guest
";
echo "Приветствую, пользователь!";

Сделать подмену в этом случае уже будет сложно. Но всё же - возможно. Для этого необходимо позаботится о том, чтобы были предусмотрены инструменты оперативного реагирования. Если необходимо в PHP включить глобальные переменные, то можно использовать следующий инструмент: если мы знаем, в каком диапазоне будет полученное значение, можно прописать, чтобы скрипт проверял это с помощью сопоставления. Конечно, это тоже не гарантирует полноценную защиту от подмены значений. Но вот перебор возможных вариантов значительно усложнит.

Находит попытку подмены

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

if (isset($_COOKIE["C_COOKIE"])) {
} elseif (isset($_GET["C_COOKIE"]) || isset($_POST["C_COOKIE"])) {

Mail("[email protected]", "Внимание, скриптом была зафиксирована попытка взлома и подмены данных", $_SERVER["REMOTE_ADDR"]);
echo "Была нарушена безопасность или попытка так сделать. Администратор уведомлён";
exit;

} else {
}
?>

А теперь пояснения к нему. Переменная C_COOKIE приходит к нам из достоверного источника. Чтобы полностью в убедится в соответствии результата ожидаемому, мы проверяем её значение и в случае проблем уведомляем об этом администратора. Если же ничего не пришло, то никаких действий и не нужно совершать. Нужно понимать, что простое отключение директивы register_globals не делает ваш код безопасным. Поэтому любая переменная, которую получает скрипт от пользователя, должна быть проверена на ожидаемое значение.

Заключение

Вот, в общем, и всё, что необходимо знать про глобальные переменные, чтобы успешно и безопасно использовать их в своей деятельности. Конечно, сказать, что существует полноценная гарантия того, что ними никто не воспользуется нельзя - взломщики постоянно совершенствуют свои методы и умения. Поэтому желательно по максимуму ограничить использование глобальных переменных в коде. Благо, структура и особенности построения этого языка программирования позволяют достичь данной цели. Успехов!