全局变量最佳实践
我们可以用下面的伪代码来说明这个问题
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 或更高版本包括扩展类型声明,你还可以使用标量类型(如 int
或 string
)。
Version = 4.1
超全局变量
PHP 中的超级全局变量是预定义变量,它们始终可用,可以从整个脚本的任何范围访问。
没有必要做全局$变量; 在函数/方法,类或文件中访问它们。
这些 PHP 超全局变量如下所示: