변수 유효영역

변수의 유효영역은 변수가 정의된 환경을 말합니다. 대부분의 경우 모든 PHP 변수는 한군데의 유효영역만을 갖습니다. 이 한군데의 유효영역은 include되거나 require된 파일로도 확장됩니다. 예를 들면:

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

위 예제코드에서는 include된 b.inc 스크립트안에서도 $a 변수가 사용가능합니다. 하지만, 사용자-선언 함수에서는 로컬 함수 유효영역이 적용됩니다. 함수내에서 사용되는 모든 변수는 기본값으로 로컬 변수 유효영역 안으로 제한됩니다. 예를 들면:

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

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

test();
?>
                  
                

echo 문이 $a 변수의 로컬 버전을 참조하고 이 범위 내에서 값이 할당되지 않았기 때문에 이 스크립트는 출력을 생성하지 않습니다. 로컬 정의에 의해 특별히 재정의되지 않는 한 C의 전역 변수를 함수에 자동으로 사용할 수 있다는 점에서 이것이 C 언어와 약간 다르다는 것을 알 수 있습니다. 이것은 사람들이 실수로 전역 변수를 변경할 수 있다는 몇 가지 문제를 일으킬 수 있습니다. PHP에서 전역 변수는 해당 함수에서 사용하려는 경우 함수 내에서 global으로 선언되어야 합니다.

global 키워드

먼저 global 사용 예:

예제 #1 global 사용

                  
<?php
$a = 1;
$b = 2;

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

    $b = $a + $b;
}

Sum();
echo $b;
?>
                  
                

위 스크립느는 "3"을 출력할 것입니다. $a$b를 함수내에서 global로 선언함으로써, 각 변수에 대한 모든 참조는 전역 버전으로 참조될 것입니다. 함순에서 조작되는 전역변수의 수는 제한이 없습니다.

전역 유효영역의 변수에 접근할 수 있는 두번째 방법이 특별 PHP-선언 $GLOBALS 배열을 사용하는 것입니다. 이전 예제코드는 다음과 같이 다시 작성할 수 있습니다:

예제 #2 global 대신 $GLOBALS 사용하기

                  
<?php
$a = 1;
$b = 2;

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

Sum();
echo $b;
?>
                  
                

$GLOBALS 배열은 전역변수명이 key가 되는 연관배열이고 배열의 원소 값이 그 변수의 내용이 됩니다. $GLOBALS이 어떻게 모든 유효영역에서 존재하는지 주의하세요. 이유는 $GLOBALS슈퍼전역변수이기 때문입니다. 아래에 슈퍼전역변수의 파워를 설명하는 예제코드를 볼 수 있습니다:

예제 #3 슈퍼글로벌과 범위를 보여주는 예

                  
<?php
function test_superglobal()
{
    echo $_POST['name'];
}
?>
                  
                

메모: 함수 외부에서 global 키워드를 사용하는 것은 오류가 아닙니다. 함수 내부에서 파일이 포함된 경우 사용할 수 있습니다.

정적(static) 변수 사용하기

변수 범위 지정의 또 다른 중요한 기능은 정적(static) 변수입니다. 정적(static) 변수는 로컬 함수 범위에만 존재하지만 프로그램 실행이 이 범위를 벗어날 때 값을 잃지 않습니다. 다음 예를 고려하십시오.

예제 #4 정적 변수의 필요성을 보여주는 예

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

이 함수는 호출될 때마다 $a0으로 설정하고 0을 인쇄하기 때문에 매우 쓸모가 없습니다. 변수를 증가시키는 $a++는 함수가 종료되자마자 $a 변수가 사라지기 때문에 아무 소용이 없습니다. 현재 카운트를 추적하지 않는 유용한 계산 함수를 만들기 위해 $a 변수를 정적으로 선언합니다.

예제 #5 정적 변수의 사용 예

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

이제 $a는 함수의 첫 번째 호출에서만 초기화되고 test() 함수가 호출될 때마다 $a의 값을 인쇄하고 증가시킵니다.

정적 변수는 또한 재귀 함수를 처리하는 한 가지 방법을 제공합니다. 재귀 함수는 자신을 호출하는 함수입니다. 재귀 함수를 무한정 재귀하게 만들 수 있으므로 재귀 함수를 작성할 때 주의해야 합니다. 재귀를 종료하는 적절한 방법이 있는지 확인해야 합니다. 다음의 간단한 함수는 정지할 때를 알기 위해 정적 변수 $count를 사용하여 10까지 재귀적으로 계산합니다.

예제 #6 재귀 함수가 있는 정적 변수

                  
<?php
function test()
{
    static $count = 0;

    $count++;
    echo $count;
    if ($count < 10) {
        test();
    }
    $count--;
}
?>
                  
                

정적 변수에는 상수 표현식의 결과인 값을 할당할 수 있지만 함수 호출과 같은 동적 표현식은 구문 분석 오류를 발생시킵니다.

예제 #7 정적 변수 선언

                  
<?php
function foo(){
    static $int = 0;          // correct
    static $int = 1+2;        // correct
    static $int = sqrt(121);  // wrong  (as it is a function)

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

메모: 정적 선언은 컴파일 타임에 해결됩니다.

전역(global) 및 정적(static) 변수를 사용한 참조

PHP는 참조 측면에서 변수에 대한 정적(static) 및 전역(global) 수정자를 구현합니다. 예를 들어, 전역(global) 문을 사용하여 함수 범위 내에서 가져온 실제 전역(global) 변수는 실제로 전역 변수에 대한 참조를 생성합니다. 이로 인해 다음 예제에서 해결하는 예기치 않은 동작이 발생할 수 있습니다.

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

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

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

위의 예는 다음을 출력합니다.

NULL
object(stdClass)#1 (0) {
}
                

유사한 동작이 정적 문에 적용됩니다. 참조는 정적으로 저장되지 않습니다.

                  
<?php
function &get_instance_ref() {
    static $obj;

    echo 'Static object: ';
    var_dump($obj);
    if (!isset($obj)) {
        $new = new stdclass;
        // Assign a reference to the static variable
        $obj = &$new;
    }
    if (!isset($obj->property)) {
        $obj->property = 1;
    } else {
        $obj->property++;
    }
    return $obj;
}

function &get_instance_noref() {
    static $obj;

    echo 'Static object: ';
    var_dump($obj);
    if (!isset($obj)) {
        $new = new stdclass;
        // Assign the object to the static variable
        $obj = $new;
    }
    if (!isset($obj->property)) {
        $obj->property = 1;
    } else {
        $obj->property++;
    }
    return $obj;
}

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

위의 예는 다음을 출력합니다.

Static object: NULL
Static object: NULL

Static object: NULL
Static object: object(stdClass)#3 (1) {
  ["property"]=>
  int(1)
}
                

이 예는 정적 변수에 대한 참조를 할당할 때 &get_instance_ref() 함수를 두 번째로 호출할 때 기억되지 않는다는 것을 보여줍니다.