Ссылка: что такое переменная область, какие переменные доступны из того, где и что такое ошибки undefined variable?

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

Что такое "переменная область" в PHP? Доступны ли переменные из одного .php файла в другом? Почему я иногда получаю ошибки "неопределенная переменная"?

Ответы

Ответ 1

Что такое "переменная область"?

Переменные имеют ограниченный "объем" или "места, из которых они доступны". Просто потому, что вы написали $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?!?!!

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

Вам следует избегать использования глобальной области в максимально возможной степени; конечно, вы не должны "вытягивать" переменные из глобальной области в локальную область.

Ответ 2

Хотя переменные, определенные внутри области функции, не могут быть доступны извне, это не означает, что вы не можете использовать их значения после завершения этой функции. 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

Это работает только с объектами того же класса. Если объекты из разных классов (даже расширяя друг друга), поведение статических vars будет таким, как ожидалось.

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

Другим способом сохранения значений между вызовами функций является использование закрытий. Закрытие было введено в PHP 5.3. В двух словах они позволяют ограничить доступ к некоторому набору переменных внутри области функций другой анонимной функцией, которая будет единственным способом доступа к ним. Быть в закрывающих переменных могут имитировать (более или менее успешно) концепции ООП, такие как "константы класса" (если они были переданы в закрытии по значению) или "частные свойства" (если они переданы по ссылке) в структурированном программировании.

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

Ответ 3

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

<?php
$a = 1;
include 'b.inc';
?>

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

<?php
$a = 1; /* global scope */ 

function test()
{ 
    echo $a; /* reference to local scope variable */ 
} 

test();
?>

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

Ответ 4

Я не буду публиковать полный ответ на этот вопрос, поскольку существующие и руководство по 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 с MIME-типами application/x-www-form-urlencoded или multipart/form-data
  • $_FILES - Файлы, переданные в HTTP-запросе POST с MIME-типом multipart/form-data
  • $_COOKIE - куки передаются с текущим запросом
  • $_SESSION - переменные сессии хранятся внутри PHP
  • $_REQUEST - Обычно это комбинация $_GET и $_POST, но иногда $_COOKIES. Содержание определяется директивой request_order в php.ini.
  • $_ENV - переменные окружения текущего скрипта