假设你有一个这样的程序:
$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'对象是一个实际的对象(就像在一个类的实例化中一样),那么你只需要为它提供一个返回必要数据的静态函数。该函数可以从任何地方访问,包括在您的身份验证函数中。