为什么在PHP或其他语言中使用动态变量(可变变量)

Why use dynamic variables (variable variables) in PHP or other languages

我最近刚刚在 PHP 中了解到动态变量的概念。对我来说,似乎在程序中使用动态变量会使 read/follow.

变得困难

任何人都可以向我解释一下好处 and/or 分享一个真实简单的现实世界示例,说明何时可能需要 PHP 中的动态变量?

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

我曾投票关闭这个问题(投票后撤回),因为它是主观的,但经过反思,我想我可以给出一个 objective 答案。

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

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

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

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

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

另一个例子可能是您继承了一些粗制滥造的意大利面条式代码,其中 "needs must" 并且使用动态命名 - 无论出于何种原因 - 可能是一个好方法。

PHP的负担结束于提供编写代码的机制;它并没有说明所述代码的设计质量。这就是代码审查的目的。

A variable variable,只是 reflection 的另一种形式。你基本上是在问 "Why would you ever want to change a variable, if you don't know it before runtime".

虽然技术上不一样,但您可以将 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 方式中,我可以将项目推入数组并在时机成熟时翻转它们,在 "normal" 方式中我需要一个 switchif 来循环通过数组然后手动添加每个选项。