php 参考:什么是变量作用域,哪些变量可以从哪里访问,什么是“未定义变量”错误?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16959576/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Reference: What is variable scope, which variables are accessible from where and what are "undefined variable" errors?
提问by deceze
Note: This is a reference question for dealing with variable scope in PHP. Please close any of the many questions fitting this pattern as a duplicate of this one.
注意:这是PHP中处理变量作用域的参考题。请关闭符合此模式的许多问题中的任何一个作为此问题的副本。
What is "variable scope" in PHP? Are variables from one .php file accessible in another? Why do I sometimes get "undefined variable"errors?
PHP 中的“变量范围”是什么?一个 .php 文件中的变量是否可以在另一个文件中访问?为什么我有时会收到“未定义变量”错误?
回答by deceze
What is "variable scope"?
什么是“可变范围”?
Variables have a limited "scope", or "places from which they are accessible". Just because you wrote $foo = 'bar';
once somewherein your application doesn't mean you can refer to $foo
from everywhereelse 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.
变量具有有限的“范围”或“可访问的位置”。仅仅因为您在应用程序的某个地方写过$foo = 'bar';
一次并不意味着您可以从应用程序内的其他任何地方引用。变量有一定的范围,在该范围内它是有效的,只有在同一范围内的代码才能访问该变量。$foo
$foo
How is a scope defined in PHP?
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 globalscope. Any variable declared outside of any function is within this global scope.
很简单:PHP 有函数 scope。这是 PHP 中存在的唯一一种范围分隔符。函数内的变量仅在该函数内可用。函数外的变量可以在函数外的任何地方使用,但不能在任何函数内使用。这意味着 PHP 中有一个特殊的作用域:全局作用域。在任何函数之外声明的任何变量都在此全局范围内。
Example:
例子:
<?php
$foo = 'bar';
function myFunc() {
$baz = 42;
}
$foo
is in the globalscope, $baz
is in a localscope inside myFunc
. Only code inside myFunc
has access to $baz
. Only code outsidemyFunc
has access to $foo
. Neither has access to the other:
$foo
在全局范围内,$baz
在局部范围内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
Scope and included files
范围和包含的文件
File boundaries do not separatescope:
文件边界不分隔范围:
a.php
一个.php
<?php
$foo = 'bar';
b.php
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:
适用于include
d 代码的规则与适用于任何其他代码的规则相同:只有function
s 单独的作用域。出于范围的目的,您可能会考虑包含诸如复制和粘贴代码之类的文件:
c.php
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 appearto 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.
在上面的例子中,a.php
被包含在 里面myFunc
,里面的任何变量都a.php
只有局部函数作用域。仅仅因为它们似乎在全局范围内a.php
并不一定意味着它们在,它实际上取决于包含/执行代码的上下文。
What about functions inside functions and classes?
函数和类中的函数呢?
Every new function
declaration introduces a new scope, it's that simple.
每一个新的function
声明都会引入一个新的作用域,就这么简单。
(anonymous) functions inside functions
函数内的(匿名)函数
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
What is scope good for?
范围有什么用?
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.
处理范围问题似乎很烦人,但有限的变量范围对于编写复杂的应用程序至关重要!如果您声明的每个变量都可以从应用程序内的其他任何地方使用,那么您将遍历所有变量,而没有真正的方法来跟踪什么改变了什么。您可以为变量指定的合理名称只有这么多,您可能希望$name
在不止一个地方使用变量“ ”。如果您的应用程序中只能有一次这个唯一的变量名称,您将不得不求助于非常复杂的命名方案,以确保您的变量是唯一的,并且您不会从错误的代码段更改错误的变量。
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...
如果没有作用域,上面的函数会做什么?哪里$bar
来的呢?它有什么状态?它甚至被初始化了吗?每次都要检查吗?这是不可维护的。这让我们...
Crossing scope boundaries
跨越范围边界
The right way: passing variables in and out
正确的方法:传入和传出变量
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 returnsa value. The caller has the confidence to know what variables the function will work with and where its return values come from:
该变量$bar
作为函数参数显式进入此范围。看看这个函数就很清楚它使用的值来自哪里。然后它显式地返回一个值。调用者有信心知道函数将使用哪些变量以及它的返回值来自哪里:
$baz = 'baz';
$blarg = foo($baz);
Extending the scope of variables into anonymous functions
将变量的范围扩展到匿名函数中
$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 globalscope.
匿名函数$foo
从其周围范围显式包含。请注意,这与全局作用域不同。
The wrong way: global
错误的方法: global
As said before, the global scope is somewhat special, and functions can explicitly import variables from it:
如前所述,全局作用域有些特殊,函数可以显式地从中导入变量:
$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!)
该函数使用和修改全局变量$foo
。不要这样做!(除非你真的真的真的真的很清楚自己在做什么,即使那样:不要!)
All the caller of this function sees is this:
这个函数的调用者看到的是:
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 requiringsome global state. You want functions to be stateless, acting only on their inputs and returning defined output, however many times you call them.
没有迹象表明此功能有任何副作用,但确实如此。这很容易变成一团糟,因为一些函数不断修改并需要一些全局状态。您希望函数是无状态的,只对它们的输入起作用并返回定义的输出,无论您调用它们多少次。
You should avoid using the global scope in any way as much as possible; most certainly you should not be "pulling" variables out of the global scope into a local scope.
您应该尽可能避免以任何方式使用全局作用域;当然,您不应该将全局范围内的变量“拉”到局部范围内。
回答by 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.
尽管在函数作用域内定义的变量不能从外部访问,但这并不意味着在该函数完成后您不能使用它们的值。PHP 有一个众所周知的static
关键字,它在面向对象的 PHP 中广泛用于定义静态方法和属性,但应该记住,它static
也可以在函数内部使用来定义静态变量。
What is it 'static variable'?
什么是“静态变量”?
Static variable differs from ordinary variable defined in function's scope in case that it does not loose value when program execution leaves this scope. Let's consider the following example of using static variables:
静态变量与函数作用域中定义的普通变量不同,它在程序执行离开此作用域时不会丢失值。让我们考虑以下使用静态变量的示例:
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.
如果我们$counter
没有定义,static
那么每次回显的值将与$num
传递给函数的参数相同。使用static
允许构建这个简单的计数器,而无需额外的解决方法。
Static variables use-cases
静态变量用例
- To store values between consequent calls to function.
- To store values between recursive calls when there is no way (or no purpose) to pass them as params.
- To cache value which is normally better to retrieve once. For example, result of reading immutable file on server.
- 在随后的函数调用之间存储值。
- 当无法(或没有目的)将值作为参数传递时,在递归调用之间存储值。
- 缓存通常最好检索一次的值。例如,读取服务器上不可变文件的结果。
Tricks
技巧
Static variable exists only in a local function scope. It can not be accessed outside of the function it has been defined in. So you may be sure that it will keep its value unchanged until the next call to that function.
静态变量只存在于局部函数作用域中。它不能在定义它的函数之外访问。因此您可以确定它的值将保持不变,直到下一次调用该函数。
Static variable may only be defined as a scalar or as a scalar expression (since PHP 5.6). Assigning other values to it inevitably leads to a failure at least at the moment this article was written. Nevertheless you are able to do so just on the next line of your code:
静态变量只能定义为标量或标量表达式(自 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
Static function is kinda 'shared' between methods of objects of the same class. It is easy to understand by viewing the following example:
静态函数在同一类的对象方法之间有点“共享”。通过查看以下示例很容易理解:
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
This only works with objects of the same class. If objects are from different classes (even extending one another) behavior of static vars will be as expected.
这仅适用于同一类的对象。如果对象来自不同的类(甚至相互扩展),静态变量的行为将符合预期。
Is static variable the only way to keep values between calls to a function?
静态变量是在函数调用之间保持值的唯一方法吗?
Another way to keep values between function calls is to use closures. Closures were introduced in PHP 5.3. In two words they allow you to limit access to some set of variables within a function scope to another anonymous function that will be the only way to access them. Being in closure variables may imitate (more or less successfully) OOP concepts like 'class constants' (if they were passed in closure by value) or 'private properties' (if passed by reference) in structured programming.
在函数调用之间保持值的另一种方法是使用闭包。闭包是在 PHP 5.3 中引入的。简而言之,它们允许您将函数范围内的某些变量集的访问限制为另一个匿名函数,这将是访问它们的唯一方法。在闭包变量中可能会模仿(或多或少成功)OOP 概念,如结构化编程中的“类常量”(如果它们在闭包中通过值传递)或“私有属性”(如果通过引用传递)。
The latter actually allows to use closures instead of static variables. What to use is always up to developer to decide but it should be mentioned that static variables are definitely useful when working with recursions and deserve to be noticed by devs.
后者实际上允许使用闭包而不是静态变量。使用什么总是由开发人员决定,但应该提到静态变量在处理递归时绝对有用,值得开发人员注意。
回答by miken32
I won't post a complete answer to the question, as the existing ones and the PHP manualdo a great job of explaining most of this.
我不会发布这个问题的完整答案,因为现有的和PHP 手册在解释大部分内容方面做得很好。
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.
但是,这是漏掉了一个主题是的超全局变量,包括常用的$_POST
,$_GET
,$_SESSION
等这些变量始终可用,在任何范围内,没有一个数组global
声明。
For example, this function will print out the name of the user running the PHP script. The variable is available to the function without any problem.
例如,此函数将打印出运行 PHP 脚本的用户的名称。该变量可供函数使用,没有任何问题。
<?php
function test() {
echo $_ENV["user"];
}
The general rule of "globals are bad" is typically amended in PHP to "globals are bad but superglobals are alright," as long as one is not misusing them. (All these variables are writable, so they could be used to avoid dependency injection if you were really terrible.)
“全局变量是坏的”的一般规则在 PHP 中通常被修改为“全局变量是坏的但超全局变量是好的”,只要不滥用它们即可。(所有这些变量都是可写的,所以如果你真的很糟糕,它们可以用来避免依赖注入。)
These variables are not guaranteed to be present; an administrator can disable some or all of them using the variables_order
directivein php.ini
, but this is not common behaviour.
不保证这些变量存在;管理员可以通过禁用某些或所有这些variables_order
指令中php.ini
,但是这是不常见的行为。
A list of current superglobals:
当前超全局变量列表:
$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 withapplication/x-www-form-urlencoded
ormultipart/form-data
MIME types$_FILES
- Files passed in an HTTP POST request with amultipart/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 therequest_order
directiveinphp.ini
.$_ENV
- The environment variables of the current script
$GLOBALS
- 当前脚本中的所有全局变量$_SERVER
- 关于服务器和执行环境的信息$_GET
- 在 URL 的查询字符串中传递的值,与用于请求的 HTTP 方法无关$_POST
- 在带有application/x-www-form-urlencoded
或multipart/form-data
MIME 类型的 HTTP POST 请求中传递的值$_FILES
- 在具有multipart/form-data
MIME 类型的 HTTP POST 请求中传递的文件$_COOKIE
- 与当前请求一起传递的 Cookie$_SESSION
- PHP 内部存储的会话变量$_REQUEST
- 通常是$_GET
和的组合$_POST
,但有时是$_COOKIES
。内容由确定的request_order
指令在php.ini
。$_ENV
- 当前脚本的环境变量