更新:Sara指出了我上一个案例中的一个缺陷。文件loadFileWithGlobals.php
错误地加载了错误的文件—它应该加载withGlobals2.php
(现已更新)。当它出现时,对baz2
的访问将正常进行。
然而,正如我在评论中指出的那样,我坚持我最初的咆哮:在您的应用程序中依赖全局变量是一种不好的做法,因为这会使它们以后很难与其他应用程序集成。使用您的应用程序的开发人员不需要准确地查明全局首次声明的时间并将其显式推入全局范围以使该应用程序与其他应用程序集成。使用其他方式(例如单例或注册表)在您的应用程序中持久化配置。
在我的最后一篇文章中,我显然大大简化了这个问题,以至于我的示例实际上没有显示我观察到的行为。我将展示一个更详细的示例,它准确地显示了给我带来问题的行为。
首先,这与在函数或类方法中包含文件有关,这些文件然后调用在全局范围内定义值的其他文件。在最初的例子中,我展示了一个包含serendipitybootstrap文件的动作控制器方法,该文件依次加载一个在全局范围内设置多维数组变量的配置文件。如果不首先在全局范围内定义变量,这种运行serendipity的方法将失败。
现在,对于示例。
首先,让我们定义六个文件。四个设置变量,两个通过常规声明,另外两个通过使用$GLOBALS
声明。其他两个文件分别加载其中一个并对变量集进行操作。
<?php // File: withoutGlobals.php $bar = 'baz'; ?> <?php // File: withoutGlobals2.php $bar2 = 'baz2'; ?> <?php // File: withGlobals.php $GLOBALS['baz'] = 'bat'; ?> <?php // File: withGlobals2.php $GLOBALS['baz2'] = 'bat2'; ?> <?php // File: loadFileWithoutGlobals.php include dirname(__FILE__) . '/withoutGlobals2.php'; echo 'Direct access to bar2: ', $bar2, "\n";" echo 'GLOBALS access to bar2: ', $GLOBALS['bar2'], "\n"; ?> <?php // File: loadFileWithGlobals.php include dirname(__FILE__) . '/withGlobals2.php'; echo 'Direct access to baz2: ', $baz2, "\n"; echo '$GLOBALS access to baz2: ', $GLOBALS['baz2'], "\n"; ?>
现在,我将定义一个类MyFoo,它尝试以多种方式设置和访问全局值:
<?php error_reporting(E_ALL | E_STRICT); ini_set('display_errors', true); class MyFoo { public function setGlobal() { $GLOBALS['foo'] = 'bar'; } public function loadFileWithoutGlobals() { include dirname(__FILE__) . '/withoutGlobals.php'; } public function loadFileWithGlobals() { include dirname(__FILE__) . '/withGlobals.php'; } public function loadScriptThatCallsFileWithoutGlobals() { include dirname(__FILE__) . '/loadFileWithoutGlobals.php'; } public function loadScriptThatCallsFileWithGlobals() { include dirname(__FILE__) . '/loadFileWithGlobals.php'; } }
最后,我们实际尝试几个案例:
<?php $o = new MyFoo(); // Case 1; expect 'Foo: bar' $o->setGlobal(); if (isset($foo)) { echo 'Foo: ', $foo, "\n"; } else { echo \"Foo not set\n"; } // Case 2; expect 'Bar not set' $o->loadFileWithoutGlobals(); if (isset($bar)) { echo 'Bar: ', $bar, "\n"; } else { echo "Bar not set\n"; } // Case 3; expect 'Baz: bat' $o->loadFileWithGlobals(); if (isset($baz)) { echo 'Baz: ', $baz, "\n"; } else { echo "Baz not set\n"; } // Case 4; expect failure $o->loadScriptThatCallsFileWithoutGlobals(); // Case 5; expect failure $o->loadScriptThatCallsFileWithGlobals();
现在,关于能够使用$GLOBALS
声明全局变量,我错了;第一种情况,我设置了foo
,效果很好。案例2也按我的预期工作;由于变量在技术上是在与方法相同的范围内定义的,因此它不是全局的。第三种情况,我最初在上一篇文章中说没有用,但也可以用;$baz
已在全局范围内正确设置。
情况4和5是事情变得有趣的地方。在案例4中,直接访问$bar2
是可行的,因为它在技术上与其定义的范围在同一范围内。但是,如预期的那样,通过$GLOBALS
访问它会失败,因为它没有在全局范围内定义。
~~在情况5中,均无法访问;直接访问$baz2
不起作用,也不能通过$GLOBALS
访问;在这两种情况下,我都会收到一条通知,指出索引未定义。这正是导致我出现问题的确切情况,并且恰恰是那种使使用全局变量令人沮丧的不一致。~~在更新的代码中,案例5完全按照它应该的方式工作;$baz2
在全局范围内。