89
function foo () {
    global $var;
    // rest of code
}

在我的小型 PHP 项目中,我通常采用程序化方式。我通常有一个包含系统配置的变量,当我需要在函数中访问这个变量时,我会使用global $var;.

这是不好的做法吗?

4

6 回答 6

103

当人们在其他语言中谈论全局变量时,它的含义与它在 PHP 中所做的不同。那是因为变量在 PHP中并不是真正的全局变量。一个典型的 PHP 程序的范围是一个 HTTP 请求。会话变量实际上比 PHP 的“全局”变量范围更广,因为它们通常包含许多 HTTP 请求。

通常(总是?)你可以像这样调用成员函数preg_replace_callback()

preg_replace_callback('!pattern!', array($obj, 'method'), $str);

有关更多信息,请参阅回调

关键是对象已经被绑定到 PHP 上,并且在某些方面会导致一些尴尬。

不要过分关注将不同语言的标准或结构应用于 PHP。另一个常见的陷阱是试图通过将对象模型粘贴到所有内容之上来将 PHP 转变为纯 OOP 语言。

像其他任何事情一样,使用“全局”变量、过程代码、特定框架和 OOP,因为它有意义、解决问题、减少您需要编写的代码量或使其更易于维护和理解,而不是因为您认为你应该。

于 2009-10-13T01:22:52.820 回答
27

如果不小心使用全局变量,可能会使问题更难发现。假设您请求一个 php 脚本,然后收到一条警告,说您正在尝试访问某个函数中不存在的数组的索引。

如果您尝试访问的数组是该函数的本地数组,请检查该函数以查看您是否在那里犯了错误。函数的输入可能有问题,因此您检查调用函数的位置。

但是,如果该数组是全局的,您需要检查使用该全局变量的所有位置,不仅如此,您还必须弄清楚这些对全局变量的引用的访问顺序。

如果您在一段代码中有一个全局变量,则很难隔离该代码的功能。为什么要隔离功能?因此,您可以对其进行测试并在其他地方重用它。如果您有一些代码不需要测试并且不需要重用,那么使用全局变量就可以了。

于 2009-10-13T03:34:20.960 回答
17

我同意接受的答案。我要补充两点:

  1. 使用前缀,以便您可以立即将其识别为全局(例如 $g_)

  2. 在一个地方声明它们,不要将它们散布在代码周围。

于 2009-10-13T01:39:54.640 回答
7

谁能反对经验、大学学位和软件工程?不是我。我只想说,在开发面向对象的单页 PHP 应用程序时,当我知道我可以从头开始构建整个东西而不用担心命名空间冲突时,我会更开心。从头开始构建是许多人不再做的事情。他们有工作、最后期限、奖金或声誉需要关心。这些类型倾向于使用大量具有高风险的预构建代码,以至于它们根本不能冒险使用全局变量。

使用全局变量可能不好,即使它们只在程序的全局区域中使用,但我们不要忘记那些只想玩得开心并让某些东西工作的人。

如果这意味着在全局命名空间中使用一些变量(< 10),那只能在程序的全局区域中使用,就这样吧。是的,是的,MVC,依赖注入,外部代码,废话,废话,废话,废话。但是,如果您已将 99.99% 的代码包含在命名空间和类中,并且外部代码是沙盒的,那么如果您使用全局变量,世界将不会结束(我重复一遍,世界不会结束)。

一般来说,我不会说使用全局变量是不好的做法。我会说在程序的全局区域之外使用全局变量(标志等)是自找麻烦并且(从长远来看)是不明智的,因为您很容易忘记它们的状态。另外,我想说你学得越多,你对全局变量的依赖就越少,因为你会体验到追踪与它们的使用相关的错误的“乐趣”。仅此一项就会激励您找到解决同一问题的另一种方法。巧合的是,这倾向于将 PHP 人推向学习如何使用名称空间和类(静态成员等)的方向。

计算机科学领域是广阔的。如果我们因为给它贴上不好的标签而吓唬所有人不敢做某事,那么他们就会失去真正理解标签背后原因的乐趣。

如果必须,请使用全局变量,然后看看是否可以在没有它们的情况下解决问题。当您深入了解问题的真实性质而不仅仅是对问题的描述时,碰撞、测试和调试就意味着更多。

于 2017-01-10T16:47:40.513 回答
7

从结束的 SO 文档 Beta 重新发布

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

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

您的第一个问题很明显

是从哪里来$bob的?

你困惑吗?好的。您刚刚了解了为什么全局变量令人困惑并被认为是一种不好的做法。如果这是一个真正的程序,你的下一个乐趣就是去追踪所有实例$bob并希望你找到正确的一个(如果$bob在任何地方都使用,这会变得更糟)。更糟糕的是,如果其他人去定义$bob(或者您忘记并重用了该变量),您的代码可能会中断(在上面的代码示例中,有错误的对象,或者根本没有对象,会导致致命错误)。由于几乎所有 PHP 程序都使用代码,例如include('file.php');您的工作,维护这样的代码会随着您添加的文件越多而呈指数级增长。

我们如何避免全局变量?

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

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

容易理解和维护。没有人猜测$bob是在哪里设置的,因为调用者负责知道这一点(它向我们传递了我们需要知道的内容)。更好的是,我们可以使用类型声明来限制传递的内容。所以我们知道它$bob要么是Bar类的实例,要么是 的子类的实例Bar,这意味着我们知道我们可以使用该类的方法。结合标准自动加载器(自 PHP 5.3 起可用),我们现在可以追踪Bar定义的位置。PHP 7.0 或更高版本包含扩展类型声明,您还可以在其中使用标量类型(如intstring)。

于 2017-08-24T00:21:53.217 回答
1

作为:

global $my_global; 
$my_global = 'Transport me between functions';
Equals $GLOBALS['my_global']

是不好的做法(如 Wordpress $pagenow)......嗯

考虑一下:

$my-global = 'Transport me between functions';

是 PHP 错误但是:

$GLOBALS['my-global'] = 'Transport me between functions';

不是错误,连字符不会与“常见”用户声明的变量发生冲突$pagenow,例如. 并且使用 UPPERCASE 表示使用中的超全局,易于在代码中发现,或通过在文件中查找进行跟踪

如果我懒得为单个解决方案构建所有内容的类,我会使用连字符,例如:

$GLOBALS['PREFIX-MY-GLOBAL'] = 'Transport me ... ';

但在更广泛使用的情况下,我使用ONE全局变量作为数组:

$GLOBALS['PREFIX-MY-GLOBAL']['context-something'] = 'Transport me ... ';
$GLOBALS['PREFIX-MY-GLOBAL']['context-something-else']['numbers'][] = 'Transport me ... ';

后者对我来说是“可乐轻”目标或使用的良好实践,而不是每次都使用单例类来“缓存”一些数据。如果我错了或在这里遗漏了一些愚蠢的东西,请发表评论......

于 2017-10-17T05:03:05.670 回答