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


167

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

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


1
이 같은이 제목이 "정의되지 않은 변수는"당신은 부하 더 많은 결과를 얻을 수 있습니다 :) 잘하지만
데일

@ 데일, 사실은 아니야. 2 년 후 2k 조회수는 ....
Pacerier

7
@Pacerier ... 임의의 의견을 남길 적절한 시간에 대해?
Dale

@Pacerier 나는 당신이 그 의견으로 무엇을 말하려고하는지 확실하지 않습니다. "....." ... 뭐?! : P
deceze

@Dale, 지금이 제때입니다 : " Stateless " 라는 단어 가 GoogleDex에 추가 된 후 2 년 동안 문제가 정체되었지만 6 개월 만에 적중률은 문자 그대로 3 배입니다.
Pacerier

답변:


188

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

변수에는 "범위"또는 "액세스 할 수있는 위치"가 제한되어 있습니다. 애플리케이션 어딘가에$foo = 'bar'; 한 번 쓴다고 해서 애플리케이션 내 다른 에서 참조 할 수있는 것은 아닙니다 . 변수$foo$foo 에는 유효 범위 내에서 특정 범위가 있으며 동일한 범위의 코드 만 변수에 액세스 할 수 있습니다.

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

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

예:

<?php

$foo = 'bar';

function myFunc() {
    $baz = 42;
}

$foo글로벌 , 범위 $baz(A)에있다 지역 범위 안에 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.phpinside가 포함 된 경우 내부 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?!?!!

이 함수 에 부작용 이 있다는 표시는 없지만 아직 있습니다. 일부 함수는 계속 전역 상태를 수정 하고 필요로하므로 엉 키게됩니다 . 함수는 상태 비 저장 이되기를 원하며 , 입력에 대해서만 작용하고 정의 된 출력을 반환하지만 여러 번 호출합니다.

가능한 한 어떤 방식 으로든 전역 범위를 사용하지 않아야합니다. 가장 확실하게 전역 범위에서 변수를 로컬 범위로 "풀링"해서는 안됩니다.


방금 잘못된 길을global 말 했으므로 언제 사용해야하는지 알려주십시오 global. 그리고 설명해주십시오 (조금) 이란 무엇인가 static..?

@stack "올바른"방법은 없습니다 global. 항상 잘못되었습니다. 함수 매개 변수 전달이 맞습니다. static설명서에 잘 설명되어 있으며 범위와 관련이 없습니다. 간단히 말해서 "범위 전역 변수"로 생각할 수 있습니다. 여기에서 kunststube.net/static 사용법을 조금 확장하고 있습니다 .
deceze

내 간단한 생각은 PHP 변수가 전역 상태를 가질만큼 충분히 중요하다면 데이터베이스의 열을 가질 가치가 있다는 것입니다. 아마 잔인한입니다,하지만 내 평범한 프로그래밍 재치에 맞는 바보 - 증거 방법입니다
아서 Tarasov

@Arthur 포장 풀기에는 너무 많은 것들이 있습니다… ಠ_ end 이것은 제가 보증 할 접근법이 아닙니다.
사망

오늘의 일이 인수의 조금이라도 @deceze stackoverflow.com/q/51409392을 - 영업 이익은 중복 (여기)에 대해 언급하지 않는 것을 언급 include_once하고 가능성 require_once도 어딘가에 추가되어야한다; 그냥 말하면 OP는 그들의 질문을 다시 열기로 투표했다. 그들의 게시물이 특별한 경우일까요? 어떻게해야합니까?
Funk Forty Niner

10

함수 범위 내에서 정의 된 변수는 외부에서 액세스 할 수 없지만 해당 함수가 완료된 후에는 해당 값을 사용할 수 없습니다. 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하면 추가 해결 방법없이이 간단한 카운터를 만들 수 있습니다.

정적 변수 사용 사례

  1. 결과적인 함수 호출 사이에 값을 저장합니다.
  2. 매개 변수로 전달할 방법이 없거나 목적이없는 경우 재귀 호출간에 값을 저장합니다.
  3. 일반적으로 한 번 검색하는 것이 더 나은 값을 캐시합니다. 예를 들어, 서버에서 변경 불가능한 파일을 읽은 결과입니다.

트릭

정적 변수는 로컬 함수 범위에만 존재합니다. 정의 된 함수 외부에서는 액세스 할 수 없습니다. 따라서 다음에 해당 함수를 호출 할 때까지 값이 변경되지 않도록 할 수 있습니다.

정적 변수는 스칼라 또는 스칼라 식으로 만 정의 할 수 있습니다 (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

이것은 같은 클래스의 객체에서만 작동합니다. 객체가 다른 클래스 (다른 클래스로 확장)에서 온 경우 정적 변수의 동작은 예상대로입니다.

정적 변수가 함수 호출간에 값을 유지하는 유일한 방법입니까?

함수 호출간에 값을 유지하는 또 다른 방법은 클로저를 사용하는 것입니다. 클로저는 PHP 5.3에서 도입되었습니다. 즉, 함수 범위 내의 일부 변수 집합에 대한 액세스를 다른 익명 함수로 제한 할 수 있습니다. 클로저 변수에 있으면 구조화 된 프로그래밍에서 '클래스 상수'(값으로 클로저로 전달 된 경우) 또는 '개인 속성'(참조로 전달 된 경우)과 같은 OOP 개념을 모방 할 수 있습니다.

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


2

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

그러나 누락 된 하나 개의 주제는이었다 슈퍼 전역 을 포함하여 일반적으로 사용되는 $_POST, $_GET, $_SESSION, 등이 변수가없이, 어떤 범위에 항상 사용할 수 있습니다 배열 인 global선언.

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

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

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

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


현재 슈퍼 글로벌 목록 :

  • $GLOBALS -현재 스크립트의 모든 글로벌 변수
  • $_SERVER -서버 및 실행 환경에 대한 정보
  • $_GET -요청에 사용 된 HTTP 메소드에 관계없이 URL의 쿼리 문자열에 전달 된 값
  • $_POST- application/x-www-form-urlencoded또는 multipart/form-dataMIME 유형으로 HTTP POST 요청에 전달 된 값
  • $_FILESmultipart/form-data-MIME 유형으로 HTTP POST 요청에 전달 된 파일
  • $_COOKIE -현재 요청과 함께 전달 된 쿠키
  • $_SESSION -PHP에 의해 내부적으로 저장된 세션 변수
  • $_REQUEST-일반적으로 $_GET$_POST때로는 조합 $_COOKIES. 내용은의 request_order지침 에 따라 결정됩니다 php.ini.
  • $_ENV -현재 스크립트의 환경 변수
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.