在PHP中使用superglobals直接好坏?

时间:2010-08-16 23:24:52

标签: php global-variables superglobals

所以,我不是来自庞大的PHP背景 - 我想知道如果在格式良好的代码中,应该直接使用'superglobals',例如在某个函数的中间说$_SESSION['x'] = 'y';或者,就像我通常使用变量一样,最好将它们作为可以从那里使用的参数发送,例如:

class Doer {
    private $sess;
    public function __construct(&$sess) {
        $this->sess =& $sess;
    }
} 

$doer = new Doer($_SESSION);

然后使用Doer中的Doer->sess版本等。 (这种方法的优点在于它表明Doer使用$ _SESSION。)

这个问题的PHP设计方法是什么?

6 个答案:

答案 0 :(得分:13)

我想将$_SESSION$_POST$_GET$_COOKIE包装到OOP结构中。

我使用此方法来集中处理卫生和验证的代码,所有必要的isset ()检查,随机数,setcookie参数等。它还允许客户端代码更具可读性(并给出我认为它更易于维护。

可能难以强制使用这种结构,特别是如果有多个编码器。使用$_GET$_POST$_COOKIE(我相信),您的初始化代码可以复制数据,然后销毁超全局。也许一个聪明的析构函数可以使用$ _SESSION(在加载时擦除$ _SESSION,在析构函数中写回),尽管我没有尝试过。

但我通常不会使用这些强制技术。习惯了之后,在会话类之外的代码中看到$_SESSION看起来很奇怪,而且我主要是单独工作。

修改
这是一些示例客户端代码,以防它帮助某人。我确信看看任何一个主要的框架会给你更好的想法......

$post = Post::load ();  
$post->numeric ('member_age');  
$post->email ('member_email');
$post->match ('/regex/','member_field');
$post->required ('member_first_name','member_email');
$post->inSet ('member_status',array('unemployed','retired','part-time','full-time'));
$post->money ('member_salary');
$post->register ('member_last_name'); // no specific requirements, but we want access
if ($post->isValid())
{
  // do good stuff
  $firstName = $post->member_first_name;
}
else
{
  // do error stuff
}

Post及其朋友都来自实现核心验证代码的基类,添加了自己的特定功能,如表单令牌,会话cookie配置等等。

在内部,该类包含一组有效数据,这些数据在调用验证方法时从$_POST中提取,然后使用魔术__get方法将它们作为属性返回。无法以这种方式访问​​失败的字段。我的验证方法(required除外)在空字段上不会失败,并且其中许多方法使用func_get_args来允许它们一次对多个字段进行操作。某些方法(如money)会自动将数据转换为自定义值类型。

在错误的情况下,我有办法将数据转换为可以保存在会话中的格式,并用于预先填充表单并在重定向到原始表单后突出显示错误。

改进这一点的一种方法是将验证信息存储在Form类中,该类用于呈现表单并为客户端验证提供支持,以及在提交后清理数据。

答案 1 :(得分:2)

修改超全球的内容被认为是不好的做法。虽然它没有什么问题,特别是如果代码100%在你的控制之下,它可能会导致意想不到的副作用,特别是当你考虑混合源代码时。例如,如果您执行以下操作:

$_POST['someval'] = mysql_real_escape_string($_POST['someval']);

你可能会期望PHP在任何地方都会使'someval'可用也会被改变,但事实并非如此。 $_REQUEST['someval']中的副本将保持不变,仍然是原始的“不安全”版本。如果您在$ _POST上执行所有转义操作,这可能会导致无意的注入漏洞,但后来的库使用$ _REQUEST并假设它已经被转义。

因此,即使您可以修改它们,最好将超全球视为只读。如果您不得不弄乱这些值,请维护自己的并行副本,并执行维护该副本所需的任何包装/访问方法。

答案 2 :(得分:2)

我知道这个问题已经过时了,但我想补充一个答案。

马里奥处理输入的课程非常棒。

我更喜欢以某种方式包装超级全球。它可以使您的代码更容易阅读并提高可维护性。

例如,我讨厌的当前工作中有一些代码!会话变量的使用非常严重,以至于您无法在不显着影响整个站点的情况下实际更改实现。

例如,

假设您创建了一个特定于您的应用程序的Session类。

class Session
{
    //some nice code
}

你可以写下面的内容

$session = new Session();
if( $session->isLoggedIn() )
{
   //do some stuff
}

与此相反

if( $_SESSION['logged'] == true )
{
   //do some stuff
}

这看起来有点微不足道,但这对我来说很重要。假设将来的某个时候我决定要将索引的名称从“已登录”更改为“已登录”。

我现在必须到应用程序中的每个地方使用会话变量来更改它。或者,我可以保留并发现维护这两个变量。

或者如果我想检查该用户是否为管理员用户并且已登录该怎么办?我最终可能会在会话中检查两个不同的变量。但是,我可以将其封装到一个方法中并缩短我的代码。

这有助于其他程序员查看您的代码,因为它变得更容易阅读,并且他们在查看代码时不必“思考”它。他们可以转到该方法,看到只有一种方法可以登录用户。它也可以帮到你,因为如果你想让“登录”检查变得更复杂,你只需要到一个地方去改变它,而不是试图用你的IDE做全局查找并尝试改变它。

同样,这是一个简单的例子,但根据你如何使用会话,这种使用方法和类来保护访问的途径可以让你的生活更加轻松。

答案 3 :(得分:0)

我不建议通过引用传递超全球。在你的课堂上,你不清楚你正在修改的是一个会话变量。另外,请记住$ _SESSION可以在课堂外的任何地方使用。从面向对象的角度来看,通过修改与该类无关的变量,能够从该类外部修改类中的变量是错误的。拥有公共属性被认为是一种不好的做法,这甚至是最糟糕的。

答案 4 :(得分:0)

我在研究新的 PHP 框架时找到了这里。

验证输入非常重要。但是,我确实经常发现自己回到这样的代码中:

function get( $key, $default=FALSE ){
    return (isset($_GET[$key]) ? $_GET[$key]:$default);
}
function post( $key, $default=FALSE ){
    return (isset($_POST[$key]) ? $_POST[$key]:$default);
}
function session( $key, $default=FALSE ){
    return (isset($_SESSION[$key]) ? $_SESSION[$key]:$default);
}

然后我像这样使用:

$page = get('p', 'start');

$first_name = post('first_name');
$last_name = post('last_name');
$age = post('age', -1);

我发现,由于我对不同项目的验证有截然不同的要求,因此处理所有情况的任何类都必须非常庞大和复杂。所以我用普通的 PHP 编写验证代码。

答案 5 :(得分:-3)

这不是PHP的好用。

直接获取$ _SESSION变量:

$id   = $_SESSION['id'];
$hash = $_SESSION['hash'];