参考资料。什么是变量范围,哪些变量可以从哪里访问,什么是 "未定义变量 "的错误?

php scope


注:本题是处理PHP中变量作用域的参考题。请关闭任何一个符合这个模式的问题,作为本题的重复题。

What is "variable scope" in PHP? Are variables from one .php file accessible in another? Why do I sometimes get "undefined variable" errors?




Answer 1 deceze


什么是 "可变范围"?

Variables have a limited "scope", or "places from which they are accessible". Just because you wrote $foo = 'bar'; once somewhere in your application doesn't mean you can refer to $foo from everywhere else inside the application. The variable $foo has a certain scope within which it is valid and only code in the same scope has access to the variable.

PHP中如何定义一个作用域?

Very simple: PHP has function scope. That's the only kind of scope separator that exists in PHP. Variables inside a function are only available inside that function. Variables outside of functions are available anywhere outside of functions, but not inside any function. This means there's one special scope in PHP: the global scope. Any variable declared outside of any function is within this global scope.

Example:

<?php

$foo = 'bar';

function myFunc() {
    $baz = 42;
}

$foo is in the global scope, $baz is in a local scope inside myFunc . Only code inside myFunc has access to $baz . Only code outside myFunc has access to $foo . Neither has access to the other:

<?php

$foo = 'bar';

function myFunc() {
    $baz = 42;

    echo $foo;  // doesn't work
    echo $baz;  // works
}

echo $foo;  // works
echo $baz;  // doesn't work

范围和包含的文件

File boundaries do not separate scope:

a.php

<?php

$foo = 'bar';

b.php

<?php

include 'a.php';

echo $foo;  // works!

The same rules apply to include d code as applies to any other code: only function s separate scope. For the purpose of scope, you may think of including files like copy and pasting code:

c.php

<?php

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

    echo $foo;  // works
}

myFunc();

echo $foo;  // doesn't work!

In the above example, a.php was included inside myFunc , any variables inside a.php only have local function scope. Just because they appear to be in the global scope in a.php doesn't necessarily mean they are, it actually depends on which context that code is included/executed in.

那么函数和类里面的函数呢?

Every new function declaration introduces a new scope, it's that simple.

函数

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

范围有什么好处?

Dealing with scoping issues may seem annoying, but limited variable scope is essential to writing complex applications! If every variable you declare would be available from everywhere else inside your application, you'd be stepping all over your variables with no real way to track what changes what. There are only so many sensible names you can give to your variables, you probably want to use the variable " $name " in more than one place. If you could only have this unique variable name once in your app, you'd have to resort to really complicated naming schemes to make sure your variables are unique and that you're not changing the wrong variable from the wrong piece of code.

Observe:

function foo() {
    echo $bar;
}

If there was no scope, what would the above function do? Where does $bar come from? What state does it have? Is it even initialized? Do you have to check every time? This is not maintainable. Which brings us to...

跨越范围界限

正确的方法:将变量传入和传出

function foo($bar) {
    echo $bar;
    return 42;
}

The variable $bar is explicitly coming into this scope as function argument. Just looking at this function it's clear where the values it works with originate from. It then explicitly returns a value. The caller has the confidence to know what variables the function will work with and where its return values come from:

$baz   = 'baz';
$blarg = foo($baz);

将变量的范围扩展为匿名函数

$foo = 'bar';

$baz = function () use ($foo) {
    echo $foo;
};

$baz();

The anonymous function explicitly includes $foo from its surrounding scope. Note that this is not the same as global scope.

The wrong way: global

如前所述,全局作用域有些特殊,函数可以从全局作用域中显式导入变量。

$foo = 'bar';

function baz() {
    global $foo;
    echo $foo;
    $foo = 'baz';
}

This function uses and modifies the global variable $foo . Do not do this!(Unless you really really really really know what you're doing, and even then: don't!)

这个函数的调用者看到的就是这个。

baz(); // outputs "bar"
unset($foo);
baz(); // no output, WTF?!
baz(); // outputs "baz", WTF?!?!!

There's no indication that this function has any side effects, yet it does. This very easily becomes a tangled mess as some functions keep modifying and requiring some global state. You want functions to be stateless, acting only on their inputs and returning defined output, however many times you call them.

你应该尽量避免以任何方式使用全局作用域;当然,你不应该把变量从全局作用域中 "拉出 "到本地作用域中。




Answer 2 Alex Myznikov


Although variables defined inside of a function's scope can not be accessed from the outside that does not mean you can not use their values after that function completes. PHP has a well known static keyword that is widely used in object-oriented PHP for defining static methods and properties but one should keep in mind that static may also be used inside functions to define static variables.

What is it 'static variable'?

静态变量与函数作用域中定义的普通变量不同的是,当程序执行离开这个作用域时,静态变量的值不会丢失。让我们来看看下面这个使用静态变量的例子。

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

If we'd defined $counter without static then each time echoed value would be the same as $num parameter passed to the function. Using static allows to build this simple counter without additional workaround.

Static variables use-cases

  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

这只适用于同一类的对象。如果对象来自不同的类(甚至是相互扩展),静态变量的行为将如预期的那样。

Is static variable the only way to keep values between calls to a function?

另一种在函数调用之间保持值的方法是使用闭包。闭包是在PHP 5.3中引入的。用两句话来说,它们允许你将对函数范围内的某些变量集的访问限制在另一个匿名函数中,这将是访问这些变量的唯一途径。在闭包中的变量可以模仿(或多或少成功地模仿结构化编程中的 "类常量"(如果在闭包中通过值传递)或 "私有属性"(如果通过引用传递)等OOP概念。

后者实际上允许使用闭包而不是静态变量。使用什么变量总是由开发者来决定,但需要提到的是,静态变量在使用递归时绝对是非常有用的,值得开发者注意。




Answer 3 miken32


I won't post a complete answer to the question, as the existing ones and the PHP manual do a great job of explaining most of this.

But one subject that was missed was that of superglobals, including the commonly used $_POST , $_GET , $_SESSION , etc. These variables are arrays that are always available, in any scope, without a global declaration.

例如,这个函数将打印出运行PHP脚本的用户名称。这个变量对函数来说是没有任何问题的。

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

在PHP中,"globals是坏的 "的一般规则通常会被修正为 "globals是坏的,但超globals是好的",只要不误用就好。(所有这些变量都是可写的,所以如果你真的很糟糕,可以用它们来避免依赖注入)。

These variables are not guaranteed to be present; an administrator can disable some or all of them using the variables_order directive in php.ini , but this is not common behaviour.


目前的超级球星名单。

  • $GLOBALS - All the global variables in the current script
  • $_SERVER - Information on the server and execution environment
  • $_GET - Values passed in the query string of the URL, regardless of the HTTP method used for the request
  • $_POST - Values passed in an HTTP POST request with application/x-www-form-urlencoded or multipart/form-data MIME types
  • $_FILES - Files passed in an HTTP POST request with a multipart/form-data MIME type
  • $_COOKIE - Cookies passed with the current request
  • $_SESSION - Session variables stored internally by PHP
  • $_REQUEST - Typically a combination of $_GET and $_POST , but sometimes $_COOKIES . The content is determined by the request_order directive in php.ini .
  • $_ENV - The environment variables of the current script