全局变量最佳实践

我们可以用下面的伪代码来说明这个问题

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; // Make backup
     $dbConnector = Mock::create('DBConnector'); // Override

     assertTrue(foo());

     $dbConnector = $bkp; // Restore
}

我们如何避免全局?

避免全局变量的最佳方法是称为 依赖注入 的哲学。这是我们将所需工具传递给函数或类的地方。

function foo(\Bar $bob) {
    $bob->doSomething();
}

容易理解和维护。没有猜测 $bob 的设置,因为调用者有责任知道(它传递给我们我们需要知道的东西)。更好的是,我们可以使用类型声明来限制传递的内容。

所以我们知道 $bob 要么是 Bar 类的一个实例,要么是 Bar 的一个实例,这意味着我们知道我们可以使用该类的方法。结合标准自动加载器(自 PHP 5.3 开始提供),我们现在可以跟踪定义 Bar 的位置。PHP 7.0 或更高版本包括扩展类型声明,你还可以使用标量类型(如 intstring)。

Version = 4.1

超全局变量

PHP 中的超级全局变量是预定义变量,它们始终可用,可以从整个脚本的任何范围访问。

没有必要做全局$变量; 在函数/方法,类或文件中访问它们。

这些 PHP 超全局变量如下所示: