基于键将大型关联数组转换为本地变量

14

我经常想要做的一件事情是将一个大的关联数组转换为基于数组键的本地变量,通常这个数组来自POST请求(例如注册表单,有许多输入)。如果你经常使用数组中的值,那么你的代码很快就会充斥着冗长的变量名和引号。

为了避免这种情况在小的关联数组中发生,可以简单地做如下操作:

$username = $_POST['username'];
$password = $_POST['password'];

为了让示例尽可能简洁,我没有对它们进行转义,所以请放心。

你也可以这样做:

list($username, $password) = $_POST;

但是如果$_POST数组更大呢?那么这两种方法都变得繁琐。为了解决这个问题,你可以运行以下循环:

foreach($arr as $key => $value)
{
    ${$key} = $value;
}

这种方法的问题在于它分配了本地变量。如果可以调用父类中运行此循环的函数,并且该调用类中可以访问这些本地变量,那将会很好。想象一个MVC设置,每个控制器都派生自Controller类,模型也是如此。可以进行如下操作:

$this->localize($_POST);
doWhatever($username) // $username works! Assuming $_POST['username'] is defined

创建这样一个方法会导致本地变量仅保留在父类localize()函数的范围内,因此这不起作用。我一直在做的是运行相同的循环,只做了一个修改:

foreach($arr as $key => $value)
{
    $this->{$key} = $value;
}

这个方法虽然可行,但并没有真正解决最初的问题。代码中不再有括号和引号,转而到处都是 $this-> ,更不用说它正在分配从未在类中正式定义过的变量。

所以,我的问题是:是否可能创建一个函数,像我描述的localize()那样,可以从父类继承,并相对于子类创建本地变量($username 而非 $this->username)?

此外,无论您能否这样做,这是否被认为是不良实践呢?在我看来,它似乎有点 hacky,并且您正在忽略一些面向对象编程的原则。如果是这样,那么您是否使用某种解决方案来解决大型关联数组的丑陋和混乱,还是就这样处理呢?

2个回答

22
PHP的extract函数正是这样做的。它将一个哈希提取到本地命名空间中:

https://www.php.net/extract

一个重要的补充:
在使用extract()函数时,务必使用EXTR_SKIP选项,如果该函数作用于用户提供的变量名(例如$_POST提供的变量名),以防止重新定义现有变量:
$myvar = 'abc';
extract($_POST, EXTR_SKIP);  // $_POST['myvar'] won't overwrite $myvar.

2
这正是我所需要的,谢谢。如果使用EXTR_SKIP,似乎非常安全。真是太疯狂了,你可以做PHP这么多年,却错过了这些基本函数...我需要开始更多地阅读手册。 - Logan Serman
1
在我发现extract()函数之前,我已经写了五年以上的PHP代码。有许多晦涩但又非常强大的内置函数。 - leepowers

1

这是一种不好的做法,用户可以通过传递POST数组中的键来重新定义您的任何变量,这很简单,这就是register_globals的工作原理,也是为什么在5.3中弃用并在5.4中删除此功能的原因。


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