我们可以用下面的伪代码来说明这个问题
function foo() { global $bob; $bob->doSomething(); }
您的第一个问题很明显
哪里$bob来的?
你困惑吗?好。您刚刚了解了为什么全局变量会令人困惑并被视为不良做法。
如果这是一个真实的程序,那么您的下一个乐趣就是追踪所有的实例,$bob并希望找到合适的实例(如果$bob到处使用,情况会更糟)。更糟糕的是,如果其他人去定义$bob(或您忘记并重用了该变量),则代码可能会中断(在上面的代码示例中,对象错误或根本没有对象会导致致命错误)。
由于几乎所有的PHP程序都像include('file.php');您的工作维护代码那样使用代码,因此,添加的文件越多,难度就越大。
而且,这使测试您的应用程序变得非常困难。假设您使用全局变量来保持数据库连接:
$dbConnector = new DBConnector(...); function doSomething() { global $dbConnector; $dbConnector->execute("..."); }
为了对该功能进行单元测试,您必须覆盖全局$dbConnector变量,运行测试,然后将其重置为原始值,这很容易发生错误:
/** * @test */ function testSomething() { global $dbConnector; $bkp = $dbConnector; // 进行备份 $dbConnector = Mock::create('DBConnector'); // 覆写 assertTrue(foo()); $dbConnector = $bkp; // 恢复 }
我们如何避免Globals?
避免全局变量的最好方法是一种称为“依赖注入”的哲学。这是我们将所需的工具传递给函数或类的地方。
function foo(\Bar $bob) { $bob->doSomething(); }
这更容易理解和维护。没有任何猜测,$bob因为调用者有责任知道在哪里设置(它将我们需要知道的信息传递给我们)。更好的是,我们可以使用类型声明来限制正在传递的内容。
因此,我们知道它$bob可以是Bar类的实例,也可以是的子级的实例Bar,这意味着我们知道可以使用该类的方法。结合标准自动加载器(自PHP 5.3起可用),我们现在可以查找Bar定义的位置。PHP 7.0或更高版本包含扩展的类型声明,您还可以在其中使用标量类型(如int或string)。
超全局变量
PHP中的超全局变量是预定义的变量,这些变量始终可用,可以在脚本的任何作用域中进行访问。
不需要做全局变量。在函数/方法,类或文件中访问它们。
这些PHP超全局变量在下面列出:
$全球
$_SERVER
$_REQUEST
$_POST
$_GET
$_FILES
$_ENV
$_COOKIE
$_SESSION