PHP 全局变量最佳实践

示例

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

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)。

4.1

超全局变量

PHP中的超全局变量是预定义的变量,这些变量始终可用,可以在脚本的任何作用域中进行访问。

不需要做全局变量。在函数/方法,类或文件中访问它们。

这些PHP超全局变量在下面列出:

  • $全球

  • $_SERVER

  • $_REQUEST

  • $_POST

  • $_GET

  • $_FILES

  • $_ENV

  • $_COOKIE

  • $_SESSION