Php 参考:什么是变量范围,哪些变量可以从何处访问,哪些是“未定义变量”错误?

Php 参考:什么是变量范围,哪些变量可以从何处访问,哪些是“未定义变量”错误?,php,scope,Php,Scope,注意:这是一个在PHP中处理变量作用域的参考问题。请将符合此模式的许多问题中的任何一个作为此问题的副本关闭 PHP中的变量作用域是什么?一个.php文件中的变量是否可以在另一个文件中访问?为什么有时会出现未定义的变量错误?什么是变量范围? 变量的作用域或访问位置有限。就因为你写了$foo='bar';在应用程序中的某个地方引用$foo并不意味着您可以在应用程序中的任何其他地方引用$foo。变量$foo有一个特定的作用域,在该作用域内它是有效的,并且只有同一作用域中的代码才能访问该变量 如何在PH

注意:这是一个在PHP中处理变量作用域的参考问题。请将符合此模式的许多问题中的任何一个作为此问题的副本关闭

PHP中的变量作用域是什么?一个.php文件中的变量是否可以在另一个文件中访问?为什么有时会出现未定义的变量错误?

什么是变量范围? 变量的作用域或访问位置有限。就因为你写了$foo='bar';在应用程序中的某个地方引用$foo并不意味着您可以在应用程序中的任何其他地方引用$foo。变量$foo有一个特定的作用域,在该作用域内它是有效的,并且只有同一作用域中的代码才能访问该变量

如何在PHP中定义作用域? 非常简单:PHP具有函数作用域。这是PHP中唯一存在的范围分隔符。函数中的变量仅在该函数中可用。函数外的变量在函数外的任何地方都可用,但在任何函数内都不可用。这意味着PHP中有一个特殊的作用域:全局作用域。在任何函数之外声明的任何变量都在此全局范围内

例子: 范围和包含的文件 文件边界不分隔作用域:

a、 php

在上面的示例中,a.php包含在myFunc中,a.php中的任何变量都只有局部函数作用域。仅仅因为它们在a.php中似乎在全局范围内并不一定意味着它们在全局范围内,它实际上取决于代码包含/执行在哪个上下文中

函数和类中的函数呢? 每一个新的函数声明都会引入一个新的作用域,就这么简单

函数中的匿名函数 班级 什么是好的范围? 处理范围问题可能看起来很烦人,但是有限的变量范围对于编写复杂的应用程序来说是必不可少的!如果您声明的每个变量都可以从应用程序中的任何其他地方获得,那么您将无法跟踪变量的变化。您可以为变量指定的合理名称只有这么多,您可能希望在多个位置使用变量$name。如果你只能在你的应用程序中使用这个唯一的变量名一次,你就必须求助于非常复杂的命名方案,以确保你的变量是唯一的,并且你没有从错误的代码中更改错误的变量

注意:

function foo() {
    echo $bar;
}
如果没有作用域,上面的函数会做什么?美元酒吧从哪里来?它有什么州?它甚至被初始化了吗?你每次都要检查吗?这是不可维护的。这让我们想到

跨越范围边界 正确的方法:传入和传出变量 变量$bar作为函数参数显式进入此范围。只要看看这个函数,就可以清楚地知道它使用的值来自何处。然后它显式返回一个值。调用者有信心知道函数将使用哪些变量以及其返回值来自何处:

$baz   = 'baz';
$blarg = foo($baz);
将变量范围扩展到匿名函数 匿名函数显式地包含其周围范围中的$foo。请注意,这与全局范围不同

错误的道路:全球 如前所述,全局范围有些特殊,函数可以显式地从中导入变量:

$foo = 'bar';

function baz() {
    global $foo;
    echo $foo;
    $foo = 'baz';
}
此函数使用并修改全局变量$foo。不要这样做!除非你真的知道自己在做什么,即使那样:不要

此函数的调用者看到的所有内容如下:

baz(); // outputs "bar"
unset($foo);
baz(); // no output, WTF?!
baz(); // outputs "baz", WTF?!?!!
没有迹象表明这个功能有任何副作用,但它确实有。由于某些函数不断修改并需要某些全局状态,这很容易变成一团混乱。您希望函数是无状态的,只作用于它们的输入并返回定义的输出,不管您调用它们多少次


您应该尽可能避免以任何方式使用全局范围;当然,您不应该将变量从全局范围拉入局部范围。

尽管函数范围内定义的变量不能从外部访问,但这并不意味着您不能在函数完成后使用它们的值。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
2 sheep jumped over fence
5 sheep jumped over fence
9 sheep jumped over fence
如果我们定义了不带static的$counter,那么每次回显的值都将与传递给fu的$num参数相同 不客气。使用static可以构建这个简单的计数器,而无需额外的解决方法

静态变量用例 在后续函数调用之间存储值。 当没有方法或没有方法时,在递归调用之间存储值 目的将它们作为参数传递。 缓存通常最好检索一次的值。对于 例如,在服务器上读取不可变文件的结果。 诡计 静态变量仅存在于局部函数作用域中。不可能 在已定义的函数之外访问。所以你可以 请确保在下次调用之前,它将保持其值不变 这个功能

静态变量只能定义为标量或标量 自PHP5.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";
}
结果:

1 sheep jumped over fence
3 sheep jumped over fence
6 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
这仅适用于同一类的对象。如果对象来自不同的类,即使彼此扩展静态变量的行为也会如预期的那样

静态变量是在函数调用之间保持值的唯一方法吗? 在函数调用之间保留值的另一种方法是使用闭包。闭包是在PHP5.3中引入的。换句话说,它们允许您将对函数作用域中某些变量集的访问限制为另一个匿名函数,而这将是访问这些变量的唯一方法。处于闭包中的变量可能或多或少成功地模仿OOP概念,如“类常量”,如果它们是通过值在闭包中传递的,或者是“私有属性”,如果它们是在结构化编程中通过引用传递的


后者实际上允许使用闭包而不是静态变量。使用什么总是由开发人员决定的,但应该提到的是,静态变量在处理递归时绝对有用,值得开发人员注意。

我不会给出这个问题的完整答案,因为现有变量和静态变量在解释大部分问题方面做得很好

但遗漏的一个主题是,包括常用的$\u POST、$\u GET、$\u SESSION等。这些变量是在任何范围内始终可用的数组,没有全局声明

例如,此函数将打印出运行PHP脚本的用户的名称。该变量可用于函数,没有任何问题

<?php
function test() {
    echo $_ENV["user"];
}
在PHP中,globals是bad的一般规则通常被修改为globals是bad的,但超globals是可以的,只要不滥用它们。所有这些变量都是可写的,所以如果你真的很糟糕的话,它们可以用来避免依赖注入

这些变量不一定存在;管理员可以使用php.ini中的禁用部分或全部,但这不是常见的行为

当前超全局的列表:

$GLOBALS-当前脚本中的所有全局变量 $\u服务器-有关服务器和执行环境的信息 $\u GET-在URL的查询字符串中传递的值,与用于请求的HTTP方法无关 $\u POST-使用application/x-www-form-urlencoded或multipart/form数据MIME类型在HTTP POST请求中传递的值 $\u FILES-以多部分/表单数据MIME类型在HTTP POST请求中传递的文件 $\u COOKIE-与当前请求一起传递的COOKIE $\u SESSION-PHP内部存储的会话变量 $\u请求-通常是$\u GET和$\u POST的组合,但有时是$\u COOKIES。内容由php.ini中的。 $\u ENV-当前脚本的环境变量
您刚才说的global的方式不对,那么请告诉我们什么时候应该使用global?请解释一下什么是静态的。@stack没有正确的方法进行全局优化。总是错的。传递函数参数是正确的。静态在手册中解释得很好,与范围没有多大关系。简而言之,它可以被认为是一个作用域全局变量。我在这里对它的用法做了一些扩展,我的简单想法是,如果一个php变量足够重要,值得拥有一个全局状态,那么它应该在数据库中拥有一列。也许这有点过分,但这是一种适合我平庸编程的傻瓜式方法wit@Arthur那里有很多东西要打开…ಠ_ಠ 这肯定不是我赞同的方法。@deceze今天这里发生了一个小小的争论——OP提到这里的副本没有提到include_once,可能需要_once也应该添加到某个地方;只是说说而已。OP投票再次提出了他们的问题。他们的帖子会是一个特例吗?应该怎么做?
baz(); // outputs "bar"
unset($foo);
baz(); // no output, WTF?!
baz(); // outputs "baz", WTF?!?!!
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
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
function test() {
    echo $_ENV["user"];
}