PHP:全局变量的替代方案?

7
我正在从事PHP项目,并且时常在网上阅读和论坛中看到一些内容,都提到不应该使用php全局变量。注意,这并不是指PHP register_globals,因为我没有使用它。我已经进行了研究,但实际上并没有找到为什么不能用或任何替代方案。
所以,我的问题很简单。在PHP中,我是否不应该使用global关键字?此外,如果我不应该(或者应该),是否有其他替代方案?原因是,我注意到我需要访问在另一个文件中定义的变量,并且我需要在函数中引用或调用此变量,很多函数都需要这样做,而我已经厌倦了反复使用global $var_name;的代码。
有任何想法吗(还是我完全错了)?

1
“你永远不应该使用它们”这个梗并不是非常明智的建议。这在很大程度上取决于你使用它们的目的。如果你在全局/共享作用域中有超过10个变量,那么很可能会出现问题。请给出一个具体的例子/列出你的共享变量。 - mario
@mario:“如果您在全局/共享范围内有超过10个变量,则很可能会出现问题。”为什么?这是性能问题,还是其他什么原因? - callum
@callum:不,绝对不是性能问题。它只会增加名称冲突和误用的可能性,因为这只是一个微不足道的函数信号(并不是说信号本身有什么不好)。我认为在共享范围方面,“少即是多”。 - mario
好的,我同意全局变量名称冲突的风险随着全局变量数量的增加而增加。但我认为把任何特定数字作为经验法则是不明智的。风险取决于许多其他因素,例如您是否在全局名称前缀中添加了某些唯一于您的应用程序的内容以及您的代码库有多大。在单个项目中使用100个全局变量,所有变量都经过仔细的前缀和文档处理,比在另一个项目中使用一个具有通用名称的杂散全局变量要安全得多。 - callum
5个回答

3
静态类和单例模式只比全局变量好一点点。静态类仅仅是将全局变量组合在一起,但这些变量本身仍然是全局可访问的单例实例变量。单例模式也是如此。虽然它们有它们的用处,但不应该作为全局变量的普遍替代品。PHP使这一点更具诱惑力,特别是由于必须在函数中声明全局变量,而静态类则随时随地可用。
最好将变量放到一个类中(例如“AppConfig”或更具体的类)并创建该类的实例来保存特定值。然后,将该实例传递给框架中的所有方法。这样,您就不依赖于特定的Singleton实现,并且具有真正的灵活性。
但是,我必须承认,这是很多工作,特别是当你还没有经验时。因此,现在使用单例可能还可以,只要您将来感觉到您的单例程序时牢记这个答案。

2
“你没有错,你只需要为应用程序考虑一些架构。:)”
“如果在类之间有共享数据,您应该使用一个包含该共享数据并具有可由所有类访问的API以检索该变量的模型。”
“为简单起见,您可以使用Singleton来包含任何共享数据。”
PHP Patterns Page提供了Singleton的示例。 Singleton背后的思想是,您始终访问该类的相同实例(版本),因此,如果更改那里的变量,则将自动在其他地方更改。”

2

如果你编写的是面向对象的代码,全局变量就不太好。但如果你的代码是过程化的,全局变量就没问题。

如果使用对象,你需要使用依赖注入(new Object(new Collaborator))。

为了管理它,你可能需要最终使用一个依赖注入容器。

如果你开始使用静态类和单例模式,那么你实际上已经不再写100%的面向对象代码。

但总之,如果是常规过程化代码,全局变量没有问题。


我不知道为什么你得到了两个反对票;在我看来,你所写的一切都是正确的,并且回答了原始问题。 - Darren Cook
2
因为他暗示全局变量是可以的,而且他没有回避过程式编程。 - citizen conn
1
全局变量的危险在于,当你的数据可以从代码的任何地方进行更改时,无法预测其在任何给定点的值。这一点在过程式编程和面向对象编程中都是正确的。 - JW.
2
很少。过程式/命令式编程并不需要全局状态。在模块化和利用本地作用域方面,它与函数式编程的使用方法几乎没有区别。 - mario
1
@blockhead。这就是为什么他们发明了“参数”。我认为它们已经存在自1854年以来了。它们允许您向一个过程传递一个值,而这个值不必是全局的。实际上,您可以编写一个过程化程序,而不需要任何全局变量。真的! :) - GolezTrol
显示剩余6条评论

2
如其他人所说,使用全局变量并没有错;特别是在短脚本中,它实际上可以使您的代码更易读,而不是用过多的OO结构来混淆它。
但是你写道: “我需要在很多函数中使用这个变量,我有点厌倦了这么多次使用全局 $var_name; 代码。”
这表明你实际上想让所有使用 $var_name 的函数都在一个类中。作为第一阶段重构,您将从其他文件中将变量传递给构造函数,并将所有的 $var_name 引用替换为 $this->var_name,然后删除所有 global $var_name; 行。
您可能最终会拥有这个类的一个全局实例,但这是可以接受的。全局变量并不邪恶,但随着代码越来越复杂,它们应该被仔细管理和记录。
如果您还没有这本书,马丁·福勒(Martin Fowler)的《重构》是一本不错的读物,可以帮助您应对当您的100行脚本现在已经变成1000行并让您感到沮丧时。 (示例是用Java编写的,但对于PHP程序员仍然可访问。)

0
一般来说,全局变量会引入安全性和代码可维护性的问题。如果你正在使用现代 PHP,那么一个好的解决方案是创建一个静态类,作为所有需要的全局变量的容器。例如,Symfony框架中的sfConfig就是一个很好的例子。你可以查看文档和代码这里,以此为灵感制作自己的类(或者只是清理代码以在自己的项目中使用...它相当独立)。

顺便提一下,我所建议的是 单例模式 的一个示例。 - Sajid

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接