PHP中的全局变量不能按预期工作

28

我在PHP中遇到了全局变量的问题。我有一个$screen变量在一个文件中被设置,在另一个调用了一个在另一个文件中定义的initSession()的文件中要求使用它。 initSession()声明了global $screen,然后进一步处理$screen,使用在第一个脚本中设置的值。

这是如何可能的?

更令人困惑的是,如果您尝试再次设置$screen并调用initSession(),它会再次使用首次使用的值。以下代码将描述此过程。有人能否解释一下这个问题?

$screen = "list1.inc";            // From model.php
require "controller.php";         // From model.php
initSession();                    // From controller.php
global $screen;                   // From Include.Session.inc  
echo $screen; // prints "list1.inc" // From anywhere
$screen = "delete1.inc";          // From model2.php
require "controller2.php"         
initSession();
global $screen;
echo $screen; // prints "list1.inc" 

更新:
如果在调用第二个模块之前再次将$screen声明为全局变量,则initSession()方法中的$screen会得到正确更新。奇怪。


3
global $a; 的等价写法是 $a =& $GLOBALS['a'];,意思是在本地作用域内创建一个与全局变量同名的引用。在函数外部时,总是处于全局作用域中。PHP 不支持“文件作用域”。 - Matthew
7个回答

62

Global并不会使变量变为全局变量,这可能有些棘手。

Global表示将使用一个本地变量,就像它是具有更高作用域的变量一样

例如:

<?php

$var = "test"; // this is accessible in all the rest of the code, even an included one

function foo2()
{
    global $var;
    echo $var; // this print "test"
    $var = 'test2';
}

global $var; // this is totally useless, unless this file is included inside a class or function

function foo()
{
    echo $var; // this print nothing, you are using a local var
    $var = 'test3';
}

foo();
foo2();
echo $var;  // this will print 'test2'
?>

注意,全局变量很少是一个好主意。你可以99.99999%的时间在没有它们的情况下编码,如果你没有模糊的作用域,你的代码更容易维护。如果可以的话,避免使用global


我完全赞同尽可能避免使用全局变量。这段代码是我们试图稍微扩展的框架的一部分,因此我们无法避免使用全局变量,因为我们没有将它们放在那里。 - Josh Smeaton
对于类也是这样吗? - Snymax
全局变量对于简单的脚本非常有用。特别是当您拥有配置文件且面向对象不适用时。 - user1086498

16

global $foo并不意味着“将此变量设为全局变量,以便每个人都可以使用它”。global $foo的意思是“在此函数作用域内使用全局变量$foo”。

我从你的示例中假设每次你在函数内部引用$screen。如果是这样,那么您需要在每个函数中使用global $screen


6

您需要在每个引用$screen的函数中添加"global $screen",而不仅仅是在每个文件的顶部。


4

如果您在执行许多函数的任务期间需要访问大量变量,请考虑创建一个“上下文”对象来保存这些内容:

//We're doing "foo", and we need importantString and relevantObject to do it
$fooContext = new StdClass(); //StdClass is an empty class
$fooContext->importantString = "a very important string";
$fooContext->relevantObject = new RelevantObject();

doFoo($fooContext);

现在,只需将此对象作为参数传递给所有函数即可。您将不需要全局变量,并且您的函数签名保持清晰。稍后将空的StdClass替换为实际具有相关方法的类也很容易。


2

在为变量定义值之前,您必须将其声明为全局变量。


1
你的回答有什么新增的内容,可以补充之前被接受且赞数很高的回答吗?是否愿意发表评论并附上一些示例代码? - Yaroslav

1

全局作用域涵盖了包含和需要的文件,除非在函数内部使用变量,否则不需要使用全局关键字。您可以尝试使用$ GLOBALS数组。


0

除非它在函数或类中,否则它是无用的。全局意味着您可以在程序的任何部分使用变量。因此,如果全局变量未包含在函数或类中,则使用全局变量没有任何用处。


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