什么是效用全球关键字?
有什么理由偏爱一种方法而不是另一种方法?
方法1:
function exempleConcat($str1, $str2) { return $str1.$str2; }
方法2:
function exempleConcat() { global $str1, $str2; return $str1.$str2; }
什么时候使用有意义global?
global
对我来说,这似乎很危险 ……但可能只是缺乏知识。我对 文档化的 技术原因感兴趣(例如,带有示例代码,链接到文档…)。
提前致谢!
这是关于该主题的一个很好的一般性问题,我(@Gordon)会提供赏金以获取其他答案。您的答案是否与我的意见一致或给出不同的观点都无关紧要。由于该global主题不时出现,因此我们可以使用一个很好的“规范”答案进行链接。
对于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环境中。只需将请求抽象为一个对象,然后使用它即可。
$_GET
$_POST
在耦合硬编码的类名(静态,常量)的情况下,如果没有可用的类,您的函数也将不存在。当它来自相同名称空间的类时,这没什么问题,但是当您从不同名称空间开始混合时,您正在创建混乱的混乱。
以上所有因素严重限制了重用。单元测试也是如此。
另外,当您耦合到全局范围时,您的功能签名就在说谎
function fn()
是骗子,因为它声称我可以在不传递任何函数的情况下调用该函数。只有当我看到函数主体时,我才需要将环境设置为特定状态。
如果您的函数需要运行参数,则使它们显式并将其传递给:
function fn($arg1, $arg2) { // do sth with $arguments }
从签名清楚地传达了它需要被称为什么。处于特定状态不依赖于环境。你不必做
$arg1 = 'foo'; $arg2 = 'bar'; fn();
这是引入(全局关键字)与推进(参数)的问题。推入/注入依赖项时,该函数不再依赖外部。当您执行此操作时,您不必fn(1)在外部的某个地方拥有1的变量。但是,当您在$one函数内部引入全局变量时,您会耦合到全局范围,并期望它在某个地方定义了该变量。然后,该功能不再独立。
fn(1)
$one
更糟糕的是,当您在函数内部更改全局变量时,您的代码很快就会变得完全难以理解,因为您的函数到处都有副作用。
如果没有更好的例子,请考虑
function fn() { global $foo; echo $foo; // side effect: echo'ing $foo = 'bar'; // side effect: changing }
然后你做
$foo = 'foo'; fn(); // prints foo fn(); // prints bar <-- WTF!!
无法看到$foo这三行内容发生了变化。为什么要使用相同的参数调用相同的函数突然改变其输出或更改全局状态下的值?函数应为定义的输入Y执行X。始终。
$foo
当使用OOP时,这变得更加严重,因为OOP与封装有关,并且通过扩展到全局范围,您正在破坏封装。您在框架中看到的所有这些Singletons和Registries都是代码气味,应删除它们以利于依赖注入。解耦您的代码。