PHP脚本结构和作用域,避免不必要的函数参数


PHP script structure and scope to avoid unnecessary function arguments

假设你有一个这样的程序:

$info = array(
    'username'=>'jeff',
    'password'=>'kay'
);
function authenticate($user, $pass) {
    if($user == $info['username'] && $pass == $info['password']) {
        return true;
    }
    return false;
}

这段代码不起作用,因为$info数组不在authenticate()的作用域中。您必须像这样将$info作为authenticate()的参数传递:

function authenticate($info, $user, $pass) { // ... }

这感觉不对。

我当然可以在authenticate里面添加global $info;,但是感觉更不对。构建PHP程序以避免此类作用域问题的最佳实践是什么?在现代代码中,你不会看到函数要求你传递"全局"对象。如何避免不必要的函数参数?

大多数人没有注意到,但这实际上是一个非常好的问题。

许多其他语言(尤其是函数式语言)都有词法作用域。使用PHP 5.3 lambda,您可以获得该功能,但仅在lambda中。让我告诉你我的意思:

$info = array(
    'username'=>'jeff',
    'password'=>'kay'
);
$authenticate = function ($user, $pass) use ($info) {
    if ($user == $info['username'] && $pass == $info['password']) {
        return true;
    }
    return false;
}
if ($authenticate($_POST['username'], $_POST['password'])) {
    // use authenticated
}

使用use,您可以从外部作用域导入变量,但它只适用于匿名函数。这取决于你使用的是哪种风格和框架。

如果你不想定义这些内联(因为你必须把它们赋值给变量,这不是很好),我建议你跟着你的直觉走,所以把$info传递给authenticate,或者让$info成为authenticate所属类的实例变量。

在这种情况下,不使用函数会更好。例如,您可以输入:

if( authenticate($user, $pass, $info))

试题:

if( Array("username"=>$user,"password"=>$pass) == $info)

然而,作为更一般的事情,我更喜欢在需要的地方传递函数参数。我也喜欢使用关联数组,就像你有$info一样,尽可能在几个参数中有很多数据。

所以在两种可能的将变量注入作用域的方法中,都感觉不对吗?这没有意义。

构造东西的最好方法是什么?最简单的一个—如果您知道需要的参数数量以及需要的参数类型—将这些参数发送给函数。

你的示例代码是好的,没有任何问题(当然,保存$info没有被传递)。

不要再发明热水了

这真的取决于你的数据来自哪里。

给定上面的例子:

  • 如果数据存储在数据库中,则从函数作用域中的数据库中检索数据,而不是将其存储在内存中。
  • 如果你的数据存储在硬编码数组中,它可能应该在另一个文件中。然后你可以在函数中include()这个文件,$info就会在函数的作用域中。
  • 如果你的数据是硬编码的数组,因为一些奇怪的原因必须存储在主文件中,它要么需要在函数中定义,要么你必须将其作为参数传递,或者显式地将数据获取到函数的范围(使用global, $GLOBALS等)。

我想说你真正应该问自己的问题是:

"我如何优化存储和检索数据的方式,以避免范围界定问题?"

通常登录信息不会硬编码到这样的脚本中,因此这是一个相当难以展开的示例。

如果您将信息存储在数据库或文件中,那么您只需在函数中引用该数据存储,而不需要那样的全局变量。


如果你执意要这样做,你可以这样做:

function authenticate($user, $pass) {
    if(checkUser($user, $pass)) {
        // I am assuming you'll do more here than just return true   
        return true;
    }
    else {
        return false;
    }
}
function checkUser($user, $pass) {
    $info = array(
        'username'=>'jeff',
        'password'=>'kay'
    );
    if($user == $info['username'] && $pass == $info['password']){
        return true;
    }
    else {
        return false;
    }
}

这样,如果您决定更改数据存储或检查用户代码,只要它返回正确的布尔值进行身份验证,就可以了。华友世纪抽象!

编辑回复评论:

假设'global'对象是一个实际的对象(就像在一个类的实例化中一样),那么你只需要为它提供一个返回必要数据的静态函数。该函数可以从任何地方访问,包括在您的身份验证函数中。