Ссылка:Что такое область видимости переменных,какие переменные доступны откуда и какие ошибки "неопределенных переменных".

php scope


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

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




Answer 1 deceze


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

Переменные имеют ограниченную «область видимости» или «места, из которых они доступны». Просто потому, что вы написали $foo = 'bar'; Однажды где-то в вашем приложении не означает, что вы можете ссылаться на $foo из любого другого места внутри приложения. Переменная $foo имеет определенную область видимости, в которой она действительна, и только код в той же области имеет доступ к переменной.

Как определяется область видимости в PHP?

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

Example:

<?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
}

classes

$foo = 'foo';

class Bar {

    public function baz() {
        // no access to $foo
        $baz = 'baz';
    }

}

// no access to $baz

Для чего хороши возможности?

Решение проблем с областями видимости может показаться раздражающим, но ограниченная область применения переменных необходима для написания сложных приложений! Если бы каждая объявленная вами переменная была бы доступна из любого места внутри вашего приложения, вы бы пошагово перебирали все переменные, не имея реального способа отследить, что и что изменится. Существует только так много разумных имен, которые вы можете дать своим переменным, вы, вероятно, захотите использовать переменную « $name » более чем в одном месте. Если бы вы могли иметь это уникальное имя переменной только один раз в своем приложении, вам пришлось бы прибегнуть к действительно сложным схемам именования, чтобы убедиться, что ваши переменные уникальны и что вы не меняете неправильную переменную из неправильного фрагмента кода.

Observe:

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?!?!!

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

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




Answer 2 Alex Myznikov


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

Что такое «статическая переменная»?

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

function countSheep($num) {
 static $counter = 0;
 $counter += $num;
 echo "$counter sheep jumped over fence";
}

countSheep(1);
countSheep(2);
countSheep(3);

Result:

1 sheep jumped over fence
3 sheep jumped over fence
6 sheep jumped over fence

Если бы мы определили $counter без static то каждый раз, когда отображаемое значение будет таким же, как параметр $num передаваемый в функцию. Использование static позволяет построить этот простой счетчик без дополнительных обходных путей.

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

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

Tricks

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

Статическая переменная может быть определена только как скалярное выражение или как скалярное выражение (начиная с 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";
}

Result:

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.В двух словах они позволяют ограничить доступ к некоторому набору переменных в области видимости функции другой анонимной функцией,которая будет единственным способом доступа к ним.Нахождение в закрытии переменных может более или менее успешно имитировать в структурированном программировании такие концепции ООП,как 'константы класса' (если они передавались при закрытии по значению)или 'приватные свойства' (если передавались по ссылке).

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




Answer 3 miken32


Я не буду публиковать полный ответ на этот вопрос, поскольку существующие и руководство по 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 - переменные окружения текущего скрипта