참조 : 변수 범위는 무엇이며, "정의되지 않은 변수"오류의 위치 및 위치에서 액세스 할 수있는 변수

php scope


참고 : 이것은 PHP에서 변수 범위를 다루기위한 참조 질문입니다. 이 패턴에 맞는 많은 질문 중 하나를이 질문의 복제본으로 닫으십시오.

PHP에서 "가변 범위"란 무엇입니까? 한 .php 파일의 변수는 다른 .php 파일에 액세스 할 수 있습니까? 때때로 "정의되지 않은 변수" 오류가 발생하는 이유는 무엇입니까?





Answer 1 deceze


"가변 범위"란 무엇입니까?

변수에는 "범위"또는 "액세스 할 수있는 위치"가 제한되어 있습니다. 당신이 $foo = 'bar'; 를 썼기 때문에 ; 응용 프로그램의 어딘가 가 응용 프로그램 내부의 다른 에서 $foo 를 참조 할 수있는 것은 아닙니다. 변수 $foo 는 유효한 특정 범위를 가지며 같은 범위의 코드 만 변수에 액세스 할 수 있습니다.

PHP에서 범위는 어떻게 정의됩니까?

매우 간단합니다 : PHP는 함수 범위를 가지고 있습니다 . 그것은 PHP에 존재하는 유일한 종류의 스코프 구분자입니다. 함수 내부의 변수는 해당 함수 내에서만 사용할 수 있습니다. 함수 외부의 변수는 함수 외부에서는 사용할 수 있지만 함수 내부에서는 사용할 수 없습니다. 이것은 PHP에 특별한 범위가 있다는 것을 의미합니다 : 글로벌 범위. 함수 외부에서 선언 된 모든 변수는이 전역 범위 내에 있습니다.

Example:

<?php

$foo = 'bar';

function myFunc() {
    $baz = 42;
}

$foo전역 범위에 있고 $bazmyFunc 내의 로컬 범위에 있습니다. 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!

다른 코드에 적용되는 것과 동일한 규칙이 d 코드를 include 하는 데 적용됩니다. 범위 목적을 위해 복사 및 붙여 넣기 코드와 같은 파일을 포함하는 것을 고려할 수 있습니다.

c.php

<?php

function myFunc() {
    include 'a.php';

    echo $foo;  // works
}

myFunc();

echo $foo;  // doesn't work!

위의 예제에서 a.phpmyFunc 안에 포함되었으며 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는 정적 메소드와 속성을 정의하기 위해 객체 지향 PHP에서 널리 사용되는 잘 알려진 static 키워드를 가지고 있지만 정적 변수를 정의하기 위해 함수 내에서 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

static 없이 $counter 를 정의했다면 에코 된 값이 매번 함수에 전달 된 $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에서 도입되었습니다. 즉, 함수 범위 내의 일부 변수 집합에 대한 액세스 권한을 다른 익명 함수로 제한 할 수 있습니다. 클로저 변수에 있으면 구조화 된 프로그래밍에서 '클래스 상수'(값으로 클로저로 전달 된 경우) 또는 '개인 속성'(참조로 전달 된 경우)과 같은 OOP 개념을 모방 할 수 있습니다.

후자는 실제로 정적 변수 대신 클로저를 사용할 수 있습니다. 사용하는 것은 항상 개발자의 결정에 달려 있지만 정적 변수는 재귀 작업을 할 때 확실히 유용하며 개발자가 주목할 가치가 있음을 언급해야합니다.




Answer 3 miken32


나는 기존의 것들과 PHP 매뉴얼 이 이것의 대부분을 설명하는 훌륭한 일을하기 때문에 질문에 대한 완전한 대답을 게시하지 않을 것입니다.

그러나 빠뜨린 한 가지 주제는 일반적으로 사용되는 $_POST , $_GET , $_SESSION 등을 포함하여 superglobals의 주제였습니다. 이러한 변수는 global 선언없이 모든 범위에서 항상 사용 가능한 배열입니다.

예를 들어,이 함수는 PHP 스크립트를 실행하는 사용자의 이름을 인쇄합니다. 변수는 문제없이 함수에 사용 가능합니다.

<?php
function test() {
    echo $_ENV["user"];
}

"글로벌이 나쁘다"라는 일반적인 규칙은 일반적으로 PHP에서 오용하지 않는 한 "글로벌은 나쁘지만 슈퍼 글로벌은 괜찮습니다"로 수정됩니다. (이러한 모든 변수는 쓰기 가능하므로 실제로 끔찍한 경우 종속성 주입을 피하는 데 사용할 수 있습니다.)

이러한 변수는 존재하지 않을 수 있습니다. 관리자는 php.ini variables_order 지시문 을 사용하여 일부 또는 전부를 비활성화 할 수 있지만 일반적인 동작은 아닙니다.


현재 슈퍼 글로벌 목록 :

  • $GLOBALS 현재 스크립트의 모든 글로벌 변수
  • $_SERVER 서버 및 실행 환경에 대한 정보
  • $_GET 요청에 사용 된 HTTP 메소드에 관계없이 URL의 쿼리 문자열에 전달 된 값
  • $_POST - application/x-www-form-urlencoded 또는 multipart/form-data MIME 유형으로 HTTP POST 요청에 전달 된 값
  • $_FILES - multipart/form-data MIME 유형으로 HTTP POST 요청에 전달 된 파일
  • $_COOKIE 현재 요청과 함께 전달 된 쿠키
  • $_SESSION -PHP에 의해 내부적으로 저장된 세션 변수
  • $_REQUEST 일반적으로 $_GET$_POST 의 조합이지만 때로는 $_COOKIES 입니다. 내용은 php.ini request_order 지시어 에 의해 결정됩니다.
  • $_ENV 현재 스크립트의 환경 변수