function foo () {
global $var;
// rest of code
}
在我的小型PHP项目中,我通常采用过程方式。通常,我有一个包含系统配置的变量,当我需要在函数中访问此变量时,我会这样做global $var;
。
这是不好的做法吗?
function foo () {
global $var;
// rest of code
}
在我的小型PHP项目中,我通常采用过程方式。通常,我有一个包含系统配置的变量,当我需要在函数中访问此变量时,我会这样做global $var;
。
这是不好的做法吗?
Answers:
当人们谈论其他语言的全局变量时,这意味着与PHP有所不同。那是因为变量在PHP中并不是真正的全局变量。典型的PHP程序的范围是一个HTTP请求。会话变量实际上比PHP“全局”变量具有更大的范围,因为它们通常包含许多HTTP请求。
通常(总是?),您可以在像preg_replace_callback()
这样的方法中调用成员函数:
preg_replace_callback('!pattern!', array($obj, 'method'), $str);
有关更多信息,请参见回调。
关键是对象已被栓接到PHP上,并且在某些方面导致尴尬。
不要在将标准或不同语言的构造应用于PHP时过度担心自己。另一个常见的陷阱是,通过将对象模型置于一切之上,试图将PHP变成纯OOP语言。
像其他任何东西一样,使用“全局”变量,过程代码,特定的框架和OOP,因为这很有意义,可以解决问题,减少了您需要编写的代码量,或者使其更易于维护和理解,而不是因为您认为你应该。
array ($obj, 'callbackMethod')
在对的调用中使用表单的回调preg_replace_callback()
吗?(我知道,我已经成为这个OOP陷阱的猎物...)
如果不仔细使用全局变量,将很难发现问题。假设您请求一个php脚本,并且收到一条警告,提示您正在尝试访问某个函数中不存在的数组的索引。
如果您要访问的数组是该函数的本地数组,请检查该函数以查看是否在此出错。该函数的输入可能有问题,因此您要检查调用该函数的位置。
但是,如果该数组是全局数组,则需要检查使用该全局变量的所有位置,不仅如此,还必须弄清楚以什么顺序访问这些对全局变量的引用。
如果您在一段代码中包含一个全局变量,则很难隔离该代码的功能。您为什么要隔离功能?因此,您可以对其进行测试并在其他地方重复使用。如果您有一些代码,则不需要测试,也不需要重用,那么使用全局变量就可以了。
谁可以反对经验,大学学位和软件工程?不是我。我只想说,在开发面向对象的单页PHP应用程序时,当我知道我可以从头开始构建整个过程而不必担心名称空间冲突时,我会感到更加有趣。从头开始构建是许多人不再要做的事情。他们有工作,有最后期限,有奖金或有名望。这些类型倾向于使用大量具有高风险的预构建代码,以至于完全没有使用全局变量的风险。
即使只在程序的全局区域中使用全局变量,也可能是不好的选择,但不要忘了那些只想获得乐趣并使某些东西起作用的人。
如果这意味着在全局名称空间中使用几个变量(<10),则只能在程序的全局区域中使用它,那就这样吧。是的,是的,MVC,依赖项注入,外部代码,等等,等等,等等。但是,如果您将99.99%的代码包含在名称空间和类中,并且外部代码被沙盒化,则使用全局变量的世界将不会结束(我重复,世界不会结束)。
通常,我不会说使用全局变量是不好的做法。我要说的是,在程序的全局区域之外使用全局变量(标志等)会带来麻烦,并且从长远来看是不明智的,因为您可以很容易地跟踪它们的状态。另外,我想说的是,您学得越多,对全局变量的依赖就越少,因为您将体验到“追踪”与使用它们相关的错误的“乐趣”。仅此一项就可以激励您找到解决同一问题的另一种方法。巧合的是,这倾向于将PHP推向学习如何使用名称空间和类(静态成员等)的方向。
计算机科学领域广阔。如果我们因为标记不好而使每个人都害怕做某事,那么他们会失去真正理解标签背后原因的乐趣。
如果需要,请使用全局变量,然后查看是否可以在没有它们的情况下解决问题。当您深入了解问题的真实本质时,冲突,测试和调试的意义就更大了,而不仅仅是对问题的描述。
从结束的SO文档Beta重新发布
我们可以用下面的伪代码来说明这个问题
function foo() {
global $bob;
$bob->doSomething();
}
您的第一个问题很明显
哪里
$bob
来的?
你困惑吗?好。您刚刚了解了为什么全局变量令人困惑并被视为不良做法。如果这是一个真实的程序,那么您的下一个乐趣就是追踪所有的实例,$bob
并希望找到合适的实例(如果$bob
到处使用,情况会更糟)。更糟糕的是,如果其他人去定义$bob
(或您忘记并重用了该变量),则代码可能会中断(在上面的代码示例中,对象错误或根本没有对象会导致致命错误)。由于几乎所有的PHP程序都像include('file.php');
您的工作维护代码那样使用代码,因此,添加的文件越多,难度就越大。
我们如何避免Globals?
避免全局变量的最好方法是一种称为“依赖注入”的哲学。这是我们将所需的工具传递给函数或类的地方。
function foo(\Bar $bob) {
$bob->doSomething();
}
这更容易理解和维护。没有任何猜测,$bob
因为调用者有责任知道在哪里设置(它将我们需要知道的信息传递给我们)。更好的是,我们可以使用类型声明来限制正在传递的内容。因此,我们知道它$bob
可以是Bar
类的实例,也可以是的子级的实例Bar
,这意味着我们知道可以使用该类的方法。结合标准自动加载器(自PHP 5.3起可用),我们现在可以查找Bar
定义的位置。PHP 7.0或更高版本包含扩展的类型声明,您还可以在其中使用标量类型(如int
或string
)。
$bob = Bar::instance();
随时随地使用它。
如:
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';
是不是错误,hypens不会发生冲突与“普通”用户声明的变量,像$pagenow
。并且使用大写表示正在使用超全局变量,易于发现代码或跟踪文件中的查找
我使用连字符,如果我懒于为单个解决方案构建所有类的类,例如:
$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 ... ';
对于我来说,后者是关于“可乐灯”目标或用途的良好实践,而不是每次都用单例类弄乱来“缓存”某些数据。如果我在这里错了或错过了一些愚蠢的东西,请发表评论...