【问题标题】:Why use dynamic variables (variable variables) in PHP or other languages [duplicate]为什么在 PHP 或其他语言中使用动态变量(可变变量)[重复]
【发布时间】:2017-08-24 16:23:00
【问题描述】:

我最近才了解到 PHP 中动态变量的概念。对我来说,在程序中使用动态变量似乎会让人难以阅读/遵循。

谁能向我解释一下好处和/或分享一个真正简单的现实世界示例,说明何时可能需要 PHP 中的动态变量?

如果您想知道什么是动态变量以及它们是如何工作的,请查看 this question

【问题讨论】:

  • 它们通常被称为变量变量;并且仅仅因为它们存在,并不意味着你必须使用它们......通常我建议不要使用它们,因为总会有更好的选择
  • 在我看来,它也使阅读/跟随变得困难。
  • 基于这里的很多问题,人们试图弄清楚如何使用变量变量,他们通常应该命名数组键而不是创建不同的变量。
  • 感谢 cmets!我很高兴我不是唯一一个感到困惑的人。我确信某处必须有一个可靠的例子,如果一个人可能绝对需要一个动态变量,但我就是想不出一个
  • 我没有使用它们,但我可以看到它们的好处。除了访问数组 $SomeComplexArrayName["value"] 之外,您还可以让它稍微简单一些,只需使用 $value

标签: php performance optimization coding-style php-7


【解决方案1】:

我投票结束这个问题(投票后撤回),因为它是主观的,但经过反思,我认为我可以给出一个客观的答案。

静态变量名是一个字符序列,代表一个标记,底层引擎使用它作为标签来标识变量所代表的值(非常非常外行的描述)。

“字符序列”是一个字符串。 string 是表示字符串的表达式。因此,从那里可以推断,任何表示字符串的表达式都应该足以表示引用变量的标记。并且该表达式本身可以分配给一个变量,并从那里获得动态变量名称。

但这不是你问的。你问:为什么?

这样的问题不是由语言的实现者来回答的。通过他们的语言提供统一且可预测的编程接口是他们的工作。 uniform 能够通过表达式来表示字符序列,而表达式又可以由变量来表示。任务完成。

主观上,我可能会看到一些数据是从外部来源导入的,甚至数据的架构也是动态的。人们可能想以某种通用对象的方式来表示它,并且由此导致对象的属性名称也可能是动态的。这是否是解决手头问题的好方法完全是主观的,取决于开发人员的判断,以及他们在代码审查期间同行的判断。

另一个例子可能是您继承了一些“需要必须”的伪劣意大利面条代码,并且使用动态命名(无论出于何种原因)可能是一个好方法。

PHP 的负担在于提供编写代码的机制;它与所述代码的设计质量无关。这就是代码审查的目的。

【讨论】:

  • 很好的答案!感谢您花时间解释。你有一些很棒的观点!
  • 当/如果这个问题产生一个有趣的答案时,最好不要自动关闭一个问题。
【解决方案2】:

variable variable 只是reflection 的另一种形式。您基本上是在问“如果您在运行前不知道变量,为什么还要更改它”。

虽然技术上不一样,但您可以将 variable variable 视为不同类型的 hash table(或 php 中的 array)。大多数variable variables 可以重写为hash table,你不会感到惊讶。但是,如果您需要在运行时之前和之后使用变量,hash table 可能会更糟糕。

一个简单的用例可能是用户可以更改的设置。请记住,以下示例按原样是不安全的,但说明了它的目的。

<?php
/*
Simple way, if you have a limited amount of settings
*/
$settings = array();
$settings["allowAccess"] = 1;
$settings["allowModify"] = 1;
$settings["allowDelete"] = 0;

if ($result = $mysqli->query("SELECT `allowAccess`, `allowModify`, `allowDelete` FROM `user_settings` LIMIT 1"))
{
    $row = $result->fetch_array(MYSQLI_ASSOC);
    $settings["allowAccess"] = $row["allowAccess"];
    $settings["allowModify"] = $row["allowModify"];
    $settings["allowDelete"] = $row["allowDelete"];
}

/*
Now consider you have a thousand settings and you dont want to write out every setting manually.
*/
if ($result = $mysqli->query("SELECT * FROM `user_settings` LIMIT 1"))
{
    $row = $result->fetch_array(MYSQLI_ASSOC);
    foreach($row as $key => $val) {
        $settings[$key] = $val;
    }
}

/*
Both options work, but everytime you want to use a setting you have to use something like below
*/

if ($settings["allowAccess"] && $settings["allowModify"] && $settings["allowDelete"]) {
    unlink($somefile);
}

/*
Perhaps you would rather write
*/

if ($allowAccess && $allowModify && $allowDelete) {
    unlink($somefile);
}

/*
Then you can use
*/
if ($result = $mysqli->query("SELECT * FROM `user_settings` LIMIT 1"))
{
    $row = $result->fetch_array(MYSQLI_ASSOC);
    foreach($row as $key => $val) {
        //if you use extract, all columns are extracted, unless you drop them first. But perhaps you need those for something else.
        //now I extract the columns that start with allow and keep the columns like id, created, modified, etc. without the need to specify each column manually, which makes it easier if you ever decide to add another setting column. You don't need to update this part of the code.
        if (substr($key,0,5)=='allow') {
            $$key = $val; //$key = 'allowAccess', $$key == $allowAccess = $val;
        }   
    }
}
?>

这只是一个例子,我在Brion VibberXHTML sanitizer for MediaWiki 中找到了另一个例子。他在他的代码中使用了很多数组,有一次他需要将它们全部翻转。他使用了下面的代码:

<?php
$vars = array( 'htmlpairs', 'htmlsingle', 'htmlsingleonly', 'htmlnest', 'tabletags',
                'htmllist', 'listtags', 'htmlsingleallowed', 'htmlelements' );
foreach ( $vars as $var ) {
    $$var = array_flip( $$var );
}

?>

现在显然他可以编写下面的代码,但这真的更容易阅读吗?

<?php                                   
$htmlpairs = array_flip($htmlpairs);
$htmlsingle = array_flip($htmlsingle);
$htmlsingleonly = array_flip($htmlsingleonly);
$htmlnest = array_flip($htmlnest);
$tabletags = array_flip($tabletags);
$htmllist = array_flip($htmllist);
$listtags = array_flip($listtags);
$htmlsingleallowed = array_flip($htmlsingleallowed);
$htmlelements = array_flip($htmlelements);
?>

这还引入了另一个用例:如果我想动态决定要翻转哪些数组怎么办?在variable variable 方式中,我可以将项目推入数组并在时机成熟时翻转它们,在“正常”方式中,我需要switchif 来循环遍历数组,然后添加每个选项手动。

【讨论】:

  • 有趣的例子。这让我想到另一个问题,为什么要使用数组翻转?
  • 我在this answer 中使用它来比较 PHP 中两个字符串的部分相似性。基本上,当您必须多次检查数组是否包含某个值时,您会使用它。通过翻转一次,您可以使用array_key_exists 而不是不断循环整个数组以查看它是否包含该值。但是虽然这个例子使用了array_flip,但是当你想用很多变量做某事,或者当你想动态分配你想用的变量时,你可以使用variable variables
  • foreach($row as $key =&gt; $val) { $$var = array_flip( $$var ); }extract($row) 更简单?
  • 我认为您复制了错误的部分。 extract 可以用于设置示例,但不能用于数组翻转。但即便如此:考虑设置表也有一列用于 id、active、modified。您可以轻松跳过具有可变变量的那些。为了使提取工作,您需要在调用它之前删除键。现在显然这并不难,但是如果您只想提取以“允许”开头的字段并将其他字段用于其他内容怎么办?这是一种简单的方法。但我不是在这里争论没有其他办法。我只是提供您何时可以使用它的示例。
猜你喜欢
  • 2017-02-08
  • 2014-05-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-02
  • 1970-01-01
  • 2018-05-06
  • 2010-11-03
相关资源
最近更新 更多