全球都是邪恶的
对于global关键字以及从本地作用域到全局范围(静态、单列、注册表、常量)的所有内容。你不想用它们。函数调用不应该依赖于外部的任何东西。function fn(){
global $foo; // never ever use that
$a = SOME_CONSTANT // do not use that
$b = Foo::SOME_CONSTANT; // do not use that unless self::
$c = $GLOBALS['foo']; // incl. any other superglobal ($_GET, …)
$d = Foo::bar(); // any static call, incl. Singletons and Registries}
所有这些都将使您的代码依赖于外部。这意味着,您必须知道应用程序所处的全部全局状态,然后才能可靠地调用这些状态。没有这个环境,函数就不可能存在。
使用超全局可能不是一个明显的缺陷,但如果从命令行调用代码,则没有$_GET或$_POST。如果您的代码依赖于这些输入,则您将自己限制在Web环境中。只需将请求抽象为一个对象,然后使用它。
在耦合硬编码类名(静态、常量)的情况下,如果没有可用的类,您的函数也不可能存在。当它是来自同一个名称空间的类时,这就不是什么问题了,但是当您从不同的名称空间开始混合时,您正在创建一个混乱的混乱。
所有这些都严重阻碍了重用。单元测试也是如此。.
此外,当您将函数签名耦合到全局范围时,您的函数签名也在撒谎。function fn()
是个骗子,因为它声称我可以调用这个函数而不把任何东西传递给它。只有当我看到功能体时,我才知道,我必须将环境设置成某种状态。
如果您的函数需要运行参数,那么将其显式化并传入:function fn($arg1, $arg2){
// do sth with $arguments}
从签名中清楚地传达了它所需要的名称。它并不取决于环境是否处于特定的状态。你不必这么做$arg1 = 'foo';$arg2 = 'bar';fn();
这是一个牵扯(全局关键字)与推入(论点)的问题。当您推入/注入依赖项时,函数不再依赖外部。当你做的时候fn(1)你不必在外面的某个地方有一个变量。但当你进入全球$one在函数中,您将耦合到全局范围,并期望它在某个地方有一个定义的变量。那么,这个函数就不再是独立的了。
更糟糕的是,当您在函数中更改全局时,您的代码将很快变得完全不可理解,因为您的函数在所有地方都有副作用。
如果没有一个更好的例子,请考虑function fn(){
global $foo;
echo $foo; // side effect: echo'ing
$foo = 'bar'; // side effect: changing}
然后你就知道了$foo = 'foo';fn(); // prints foofn(); // prints bar
我们不可能看到$foo从这三条线上变了。为什么会用相同的参数调用相同的函数,突然改变它的输出,或者在全局状态下改变一个值?函数应该对定义的输入Y执行X操作。
在使用OOP时,这会变得更加严重,因为OOP是关于封装的,通过扩展到全局范围,您就破坏了封装。您在框架中看到的所有这些单例和注册中心都是代码气味,应该删除它们以支持依赖注入。去耦合你的代码。
更多资源: