Ссылка: Что такое область видимости переменных, какие переменные доступны откуда и каковы ошибки "неопределенных переменных"?
Примечание. Это справочный вопрос для работы с переменной областью в PHP. Пожалуйста, закройте любой из множества вопросов, соответствующих этому шаблону, как дубликат этого.
Что такое "переменная область" в PHP? Доступны ли переменные из одного.php-файла в другом? Почему я иногда получаю ошибки "неопределенная переменная"?
3 ответа
Что такое "переменная область"?
Переменные имеют ограниченную "область видимости" или "места, из которых они доступны". Просто потому что ты написал $foo = 'bar';
когда- то где-то в вашем приложении не означает, что вы можете сослаться на $foo
отовсюду внутри приложения. Переменная $foo
имеет определенную область, в которой он действителен, и только код в той же области имеет доступ к переменной.
Как определяется область действия в PHP?
Очень просто: PHP имеет область действия функции. Это единственный вид разделителя области видимости, который существует в PHP. Переменные внутри функции доступны только внутри этой функции. Переменные вне функций доступны везде вне функций, но не внутри какой-либо функции. Это означает, что в PHP есть одна особая область: глобальная область. Любая переменная, объявленная вне какой-либо функции, находится в этой глобальной области видимости.
Пример:
<?php
$foo = 'bar';
function myFunc() {
$baz = 42;
}
$foo
в глобальном масштабе, $baz
находится в локальном объеме внутри myFunc
, Только код внутри myFunc
имеет доступ к $baz
, Только код снаружи myFunc
имеет доступ к $foo
, Ни один из них не имеет доступа к другому:
<?php
$foo = 'bar';
function myFunc() {
$baz = 42;
echo $foo; // doesn't work
echo $baz; // works
}
echo $foo; // works
echo $baz; // doesn't work
Область и включенные файлы
Границы файла не разделяют область видимости:
a.php
<?php
$foo = 'bar';
b.php
<?php
include 'a.php';
echo $foo; // works!
Те же правила применяются к include
код d, как и любой другой код: только function
Отдельная сфера. Для целей охвата вы можете подумать о включении таких файлов, как копия и вставка кода:
c.php
<?php
function myFunc() {
include 'a.php';
echo $foo; // works
}
myFunc();
echo $foo; // doesn't work!
В приведенном выше примере a.php
был включен внутри myFunc
любые переменные внутри a.php
иметь только локальную область действия функции. Просто потому, что они, кажется, находятся в глобальном масштабе в a.php
не обязательно означает, что они есть, это на самом деле зависит от того, в каком контексте этот код включен / выполнен.
Как насчет функций внутри функций и классов?
Каждый новый function
Объявление вводит новую область, это так просто.
(анонимные) функции внутри функций
function foo() {
$foo = 'bar';
$bar = function () {
// no access to $foo
$baz = 'baz';
};
// no access to $baz
}
классы
$foo = 'foo';
class Bar {
public function baz() {
// no access to $foo
$baz = 'baz';
}
}
// no access to $baz
Для чего нужна сфера?
Работа с областями видимости может показаться раздражающей, но ограниченная область применения переменных необходима для написания сложных приложений! Если бы каждая объявленная вами переменная была бы доступна из любого места внутри вашего приложения, вы бы пошагово перебирали все переменные, не имея реального способа отследить, что изменится. Есть только так много разумных имен, которые вы можете дать своим переменным, вы, вероятно, захотите использовать переменную "$name
"в нескольких местах. Если бы вы могли иметь это уникальное имя переменной только один раз в своем приложении, вам пришлось бы прибегнуть к действительно сложным схемам именования, чтобы убедиться, что ваши переменные уникальны и что вы не меняете неправильную переменную с неправильный кусок кода.
Заметим:
function foo() {
echo $bar;
}
Если бы не было области действия, что бы делала вышеуказанная функция? Где же $bar
родом из? В каком состоянии он находится? Это даже инициализировано? Вы должны проверять каждый раз? Это не подлежит ремонту. Что приводит нас к...
Пересекая границы границ
Правильный путь: передача переменных в и из
function foo($bar) {
echo $bar;
return 42;
}
Переменная $bar
явно входит в эту область в качестве аргумента функции. Глядя на эту функцию, становится ясно, откуда берутся значения, с которыми она работает. Затем он явно возвращает значение. Вызывающая сторона уверена, что знает, с какими переменными будет работать функция и откуда возвращаются ее значения:
$baz = 'baz';
$blarg = foo($baz);
Расширение области видимости переменных в анонимные функции
$foo = 'bar';
$baz = function () use ($foo) {
echo $foo;
};
$baz();
Анонимная функция явно включает $foo
из окружающей его области. Обратите внимание, что это не то же самое, что глобальная область.
Неправильный путь: global
Как было сказано ранее, глобальная область видимости является чем-то особенным, и функции могут явно импортировать переменные из нее:
$foo = 'bar';
function baz() {
global $foo;
echo $foo;
$foo = 'baz';
}
Эта функция использует и изменяет глобальную переменную $foo
, Не делайте этого! (Если только вы действительно действительно действительно не знаете, что делаете, и даже тогда: не надо!)
Все, что вызывает эта функция, видит так:
baz(); // outputs "bar"
unset($foo);
baz(); // no output, WTF?!
baz(); // outputs "baz", WTF?!?!!
Там нет никаких признаков того, что эта функция имеет какие-либо побочные эффекты, но это так. Это очень легко становится запутанным беспорядком, поскольку некоторые функции продолжают изменяться и требуют некоторого глобального состояния. Вы хотите, чтобы функции не имели состояния, действовали только на свои входы и возвращали определенный вывод, сколько бы раз вы их ни вызывали.
Вы должны избегать использования глобальной области видимости в максимально возможной степени; Скорее всего, вы не должны "вытягивать" переменные из глобальной области в локальную область.
Хотя переменные, определенные внутри области действия функции, не могут быть доступны извне, это не означает, что вы не можете использовать их значения после завершения этой функции. PHP хорошо известен static
ключевое слово, которое широко используется в объектно-ориентированном PHP для определения статических методов и свойств, но следует помнить, что static
может также использоваться внутри функций для определения статических переменных.
Что такое "статическая переменная"?
Статическая переменная отличается от обычной переменной, определенной в области видимости функции, в том случае, если она не теряет значение, когда выполнение программы выходит из этой области. Давайте рассмотрим следующий пример использования статических переменных:
function countSheep($num) {
static $counter = 0;
$counter += $num;
echo "$counter sheep jumped over fence";
}
countSheep(1);
countSheep(2);
countSheep(3);
Результат:
1 sheep jumped over fence
3 sheep jumped over fence
6 sheep jumped over fence
Если бы мы определили $counter
без static
тогда каждый раз отображаемое значение будет таким же, как $num
параметр передан в функцию. С помощью static
позволяет построить этот простой счетчик без дополнительных обходных путей.
Примеры использования статических переменных
- Для сохранения значений между последовательными вызовами функции.
- Хранить значения между рекурсивными вызовами, когда нет возможности (или нет цели) передать их как параметры.
- Кэшировать значение, которое обычно лучше получить один раз. Например, результат чтения неизменяемого файла на сервере.
Трюки
Статическая переменная существует только в локальной области действия функции. К нему нельзя получить доступ за пределами функции, в которой он был определен. Поэтому вы можете быть уверены, что оно сохранит свое значение без изменений до следующего вызова этой функции.
Статическая переменная может быть определена только как скаляр или скалярное выражение (начиная с PHP 5.6). Присвоение ему других значений неизбежно приводит к провалу, по крайней мере, на момент написания этой статьи. Тем не менее, вы можете сделать это только на следующей строке вашего кода:
function countSheep($num) {
static $counter = 0;
$counter += sqrt($num);//imagine we need to take root of our sheep each time
echo "$counter sheep jumped over fence";
}
Результат:
2 sheep jumped over fence
5 sheep jumped over fence
9 sheep jumped over fence
Статическая функция является своего рода "общей" для методов объектов одного и того же класса. Это легко понять, просмотрев следующий пример:
class SomeClass {
public function foo() {
static $x = 0;
echo ++$x;
}
}
$object1 = new SomeClass;
$object2 = new SomeClass;
$object1->foo(); // 1
$object2->foo(); // 2 oops, $object2 uses the same static $x as $object1
$object1->foo(); // 3 now $object1 increments $x
$object2->foo(); // 4 and now his twin brother
Это работает только с объектами одного класса. Если объекты принадлежат разным классам (даже расширяют друг друга), поведение статических переменных будет таким, как ожидалось.
Является ли статическая переменная единственным способом сохранить значения между вызовами функции?
Другой способ сохранить значения между вызовами функций - использовать замыкания. Замыкания были введены в PHP 5.3. В двух словах они позволяют вам ограничить доступ к некоторому набору переменных в области действия функции другой анонимной функции, которая будет единственным способом доступа к ним. Находящиеся в замыкании переменные могут имитировать (более или менее успешно) такие концепции ООП, как "константы класса" (если они были переданы в замыкании по значению) или "частные свойства" (если они передаются по ссылке) в структурном программировании.
Последнее фактически позволяет использовать замыкания вместо статических переменных. Что использовать, решать только разработчикам, но следует отметить, что статические переменные, безусловно, полезны при работе с рекурсиями и заслуживают того, чтобы их заметили разработчики.
Область действия переменной - это контекст, в котором она определена. По большей части все переменные PHP имеют только одну область видимости. Эта единая область действия включает и необходимые файлы. Например:
<?php
$a = 1;
include 'b.inc';
?>
Здесь $a
переменная будет доступна в рамках включенного b.inc
скрипт. Однако в определяемых пользователем функциях вводится локальная область функций. Любая переменная, используемая внутри функции, по умолчанию ограничена областью действия локальной функции. Например:
<?php
$a = 1; /* global scope */
function test()
{
echo $a; /* reference to local scope variable */
}
test();
?>
Этот сценарий не будет выдавать никаких выходных данных, поскольку оператор echo ссылается на локальную версию переменной $ a, и ей не было присвоено значение в этой области. Вы можете заметить, что это немного отличается от языка C в том, что глобальные переменные в C автоматически доступны для функций, если они специально не переопределены локальным определением. Это может вызвать некоторые проблемы в том, что люди могут случайно изменить глобальную переменную. В PHP глобальные переменные должны быть объявлены глобальными внутри функции, если они будут использоваться в этой функции.
Я не буду публиковать полный ответ на этот вопрос, поскольку существующие руководства и руководство по PHP отлично объясняют большую часть этого.
Но упустили одну тему - суперглобальные, в том числе широко используемые$_POST
, $_GET
, $_SESSION
и т.д. Эти переменные представляют собой массивы, которые всегда доступны в любой области, без global
декларация.
Например, эта функция распечатает имя пользователя, запустившего сценарий PHP. Переменная доступна функции без проблем.
<?php
function test() {
echo $_ENV["user"];
}
Общее правило "глобальные переменные - плохие" обычно изменяют в PHP на "глобальные переменные - плохие, но суперглобальные - в порядке", если никто не злоупотребляет ими. (Все эти переменные доступны для записи, поэтому их можно использовать, чтобы избежать внедрения зависимостей, если вы действительно ужасны.)
Наличие этих переменных не гарантируется; администратор может отключить некоторые или все из них с помощью variables_order
директива вphp.ini
, но это не обычное поведение.
Список текущих суперглобалов:
$GLOBALS
- Все глобальные переменные в текущем скрипте$_SERVER
- Информация о сервере и среде исполнения$_GET
- Значения, переданные в строке запроса URL-адреса, независимо от метода HTTP, используемого для запроса.$_POST
- Значения, переданные в запросе HTTP POST сapplication/x-www-form-urlencoded
илиmultipart/form-data
Типы MIME$_FILES
- Файлы, переданные в запросе HTTP POST сmultipart/form-data
Тип MIME$_COOKIE
- Файлы cookie, переданные с текущим запросом$_SESSION
- Переменные сеанса, хранящиеся внутри PHP$_REQUEST
- Обычно комбинация$_GET
а также$_POST
, но иногда$_COOKIES
. Содержание определяетсяrequest_order
директива вphp.ini
.$_ENV
- Переменные среды текущего скрипта