【问题标题】:Is there any way to dynamically access a superglobal?有没有办法动态访问超全局?
【发布时间】:2010-08-24 16:08:48
【问题描述】:

作为一名 Web 开发人员,我总是将这种方法用于登录表单或其他“保存”操作(忽略直接访问输入变量的危险):

if (isset($_POST['action']) && $_POST['action'] == 'login')
{
    // we're probably logging in, so let's process that here
}

为了减少繁琐并符合 DRY 原则(有点),我做了这个:

function isset_and_is ($superglobal, $key, $value)
{
    $ref = '_' . strtoupper($superglobal);

    return isset($$ref[$key]) && $$ref[$key] == $value;
}

if (isset_and_is('post', 'action', 'login'))
{
    // we're probably logging in, so let's process that here
}

尽管我非常聪明地使用动态变量名来访问超全局变量,但这还是失败了。

所以,我被这个丑陋的东西卡住了:

function isset_and_is ($superglobal, $key, $value)
{
    switch (strtoupper($superglobal))
    {
        case 'GET':     $ref =& $_GET;     break;
        case 'POST':    $ref =& $_POST;    break;
        case 'REQUEST': $ref =& $_REQUEST; break;
        default:        die('megafail');   return;
    }

    return isset($ref[$key]) && $ref[$key] == $value;
}

if (isset_and_is('post', 'action', 'login'))
{
    // we're probably logging in, so let's process that here
}

我的问题:有没有办法像我在第二个代码示例中尝试做的那样动态访问超全局变量?如果没有,是否有更好/更有效的方法来完成我在第三个代码示例中所做的事情?


我的解决方案:感谢Tom Haigh's answer,这是我将要使用的最终代码:

function isset_and_is ($superglobal, $key, $value)
{
    $ref =& $GLOBALS['_' . strtoupper($superglobal)];

    return isset($ref[$key]) && $ref[$key] == $value;
}

【问题讨论】:

  • 第一个样本有什么问题?
  • IMO 第一个示例更清晰、更干、更容易让任何了解 PHP 的人理解。而其他的......
  • NullUserException: 有效点,但我是唯一使用此代码的人,除非您也想使用它。
  • 好吧,如果你想给你的代码引入不必要的复杂性和开销,我能拒绝你吗? ;-)

标签: php superglobals


【解决方案1】:

你可以这样做:

function test($var) {
    //this 
    var_dump( $GLOBALS[$var] );

    //or this
    global $$var; //this is needed even for superglobals
    var_dump($$var);
}

test('_GET');

所以你可以在你的情况下使用这样的东西

function isset_and_is ($superglobal, $key, $value) {
    $var = '_' . $superglobal;
    return isset($GLOBALS[$var]) && ($GLOBALS[$var][$key] == $value);
}

$is_login = isset_and_is('GET', 'action', 'login');

或者您也可以通过引用获取变量并使用isset(),例如

function get_var(& $var) {
    if (isset($var)) {
        return $var;
    }
    return null;
}

//will not give you a notice if not set
$post_var = get_var($_POST['var']);

if (get_var($_GET['action']) == 'login') {
    //stuff
}

【讨论】:

    【解决方案2】:

    如果您只需要从一个来源获取,请使用 Tom's answer

    但是,如果您对每个变量都这样做,即,如果您始终承认数据可能来自两个来源,那么最好的选择是将它们合并。

    您可以使用$_REQUEST,但我建议您不要这样做。它认为 POST 和 GET 数据的顺序是 php.ini 可配置的,它包括其他来源。

    执行以下操作:

    $data = array_merge($_GET, $_POST); //POST has precedence
    

    然后从$data获取您的数据。

    【讨论】:

    • 这里没有 GET 优先级吗?我的意思是,如果设置了$_POST['var']$_GET['var'],它将选择$_GET['var']
    • 我不承认数据总是来自两个来源;相反,数据只会来自超全球之一,这取决于我在哪里访问它。但是,我希望能够重新使用这个功能。
    【解决方案3】:

    怎么样:http://www.php.net/manual/en/function.filter-input.php

    function isset_and_is ($superglobal, $key, $value) {
      switch($superglobal) {
        case 'post':
          $type = INPUT_POST;
          break;
        case 'get':
          $type = INPUT_GET;
          break;
      }
      $var = filter_input($type,$key);
      if(is_null($var)) return false;
      return($var == $value);
    }
    

    【讨论】:

    • 你的回答完全忽略了这个问题,只是为我的第三个代码示例提供了一个同样糟糕的解决方案。
    • 老实说,我看不出它是如何无视您的问题的。鉴于您实际上可以使用 INPUT_* 常量作为该函数的参数来摆脱开关,它成为一个非常好的解决方案恕我直言。
    【解决方案4】:

    $_REQUEST默认包含$_GET$_POST的内容时,为什么需要switch-case。你可以直接用这个,去掉$superglobal

    function isset_and_is ($key, $value)
    {
        return isset($_REQUEST[$key]) && ($_REQUEST[$key] == $value);
    }
    

    【讨论】:

    • 例如,如果我只想允许通过POST 登录,$_REQUEST 是不安全的。
    【解决方案5】:

    在 PHP 中,运算符 @ 在计算表达式时会抑制警告。例如,$array[$key] 如果存在则返回带有该键的值,否则返回 null,但如果该键不存在,则会引发警告。添加@ 运算符以生成@$array[$key] 使其等效于array_key_exists($key, $array) ? $array[$key] : null。事实上,isset($something) 只是@$something === null 的另一种说法。

    所以试试这个:

    if (@$_POST['action'] === 'login')
    {
        // we're probably logging in, so let's process that here
    }
    

    我的 PHP 项目使用类似于 documentation of ErrorException 中的 sn-p 的东西。这增加了快速失败的语义,其中 PHP $array[$key] 表示如果不存在则抛出 ErrorException@$array[$key] 表示使用 null 表示未找到(如 SQL LEFT JOIN)。

    【讨论】:

      最近更新 更多