Область видимости переменной

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


Наш чат в Telegram для обмена идеями, проектами, мыслями, людьми в сфере ИТ г.Ростова-на-Дону: @it_rostov
$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. Предыдущий пример может быть переписан так:

Пример #2 Использование $GLOBALS вместо global

$a = 1;
$b = 2;
function Sum()
{
    $GLOBALS['b'] = $GLOBALS['a'] + $GLOBALS['b'];
} 
Sum();
echo $b;

$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:

Пример #6 Статические переменные и рекурсивные функции

function test()
{
    static $count = 0;
    $count++;
    echo $count;
    if ($count < 10) {
        test();
    }
    $count--;
}

Замечание:

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

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

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

Замечание:

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

Замечание:

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


Ссылки с глобальными (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);

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


NULL
object(stdClass)(0) {
}

Аналогично ведет себя и выражение static. Ссылки не хранятся статично:

function &get_instance_ref() {
    static $obj;
    echo 'Статический объект: ';
    var_dump($obj);
    if (!isset($obj)) {
        // Присвоить ссылку статической переменной
        $obj = &new stdclass;
    }
    $obj->property++;
    return $obj;
}
function &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() во второй раз.


User Contributed Notes 58 notes



12
warhog at warhog dot net7 years ago
class sample_class
{
  public function func_having_static_var($x = NULL)
  {
    static $var = 0;
    if ($x === NULL)
    { return $var; }
    $var = $x;
  }
}
$a = new sample_class();
$b = new sample_class();
echo $a->func_having_static_var()."\n";
echo $b->func_having_static_var()."\n";
// this will output (as expected):
//  0
//  0
$a->func_having_static_var(3);
echo $a->func_having_static_var()."\n";
echo $b->func_having_static_var()."\n";
// this will output:
//  3
//  3
// maybe you expected:
//  3
//  0


6
Anonymous5 years ago
class test1{}
class test2{}
class test3{}
function cache( $class )
{
    static $loaders = array();
    
    $loaders[ $class ] = new $class();
    var_dump( $loaders );
}
print '<pre>';
cache( 'test1' );
cache( 'test2' );
cache( 'test3' );


5
php at keith tyler dot com3 years ago
print "Global scope FILENAME [$filename]\n";
class MyTestClass extends PHPUnit_Framework_TestCase {
  function testMyTest() {
    global $filename;
    print "Method scope global FILENAME [$filename]\n";
    print "Method scope GLOBALS[FILENAME] [".$GLOBALS["filename"]."]\n";
  }
}


7
HOSSEIN doesn&#39;t want spam at TAKI.IR3 years ago
function foo(){
    $f_a = 'a';
    
    function bar(){
        global $f_a;
        echo '"f_a" in BAR is: ' . $f_a . '<br />';  // doesn't work, var is empty!
    }
    
    bar();
    echo '"f_a" in FOO is: ' . $f_a . '<br />';
}


3
moraesdno at gmail dot com4 years ago
//Using the keyword global
$a=1;
$b=2;
function sum() {
    global $a, $b;
    $a += $b;
}
 $t = microtime(true);
 for($i=0; $i<1000; $i++) {
     sum();
 }
 echo microtime(true)-$t;
 echo " -- ".$a."<br />";
//Using the superglobal array
$a=1;
$b=2;
function sum2() {
    $GLOBALS['a'] += $GLOBALS['b'];
}
  $t = microtime(true);
 for($i=0; $i<1000; $i++) {
     sum2();
 }
 echo microtime(true)-$t;
 echo " -- ".$a."<br />";


3
andrew at planetubh dot com4 years ago
//declare this before include
global $myVar;
//or declare this inside the include file
$nowglobal = $GLOBALS['myVar'];


3
carpathia_uk at mail dot com12 years ago
function isLoggedin()
{
global $cookie_username;
if (isset($cookie_username) 
echo "blah..";
}


4
nullhility at gmail dot com4 years ago
class global_reference
{
    public $val;
    
    public function __construct () {
        global $var;
        $this->val = $var;
    }
    
    public function dump_it ()
    {
        debug_zval_dump($this->val);
    }
    
    public function type_cast () 
    {
        $this->val = (int) $this->val;
    }
}
$var = "x";
$obj = new global_reference();
$obj->dump_it();
$obj->type_cast();
echo "after change ";
$obj->dump_it();
echo "original $var\n";


2
pangxiezhou at gmail dot com1 year ago
        function test() {
                static $local_var=0;
                $local_var=9;
                echo $local_var++;
            }
        test();
        test();