PHP变量变量与数组键

8

我在想是否有方法可以解决这个问题(或者这个问题是否能够被解决)。

我有一段类似于这样的代码。我有一个字符串,其中包含方括号,类似于访问数组键时使用的方括号。我想通过使用该字符串的值来创建该数组键本身。我希望这段代码能更好地解释我的意思。

// String that has a value similar to an array key
$string = 'welcome["hello"]';
$$string = 'thisworks';

// I could then print the array keys value like this
print( $welcome["hello"] );

// This would hopefully output 'thisworks'.

然而似乎无法使其正常工作,这是否可能(或者还有其他方法可以解决)?


你是在尝试解析JSON吗?如果可以的话,请更详细地描述一下这些数据的来源。 - Cory Carson
2
从一开始就使用数组,这样就不会有这些问题。 - hakre
不使用JSON。这只是一个非常简化的版本,但本质上是使用多维数组来构建新的选项数组。目前我正在使用regexp来检测字符串是否包含方括号,如果包含,则if语句会执行大量操作以创建一个数组。正如您所猜测的那样,尝试使上述方法工作将节省所有if检查,并且将适用于既不包含方括号也包含方括号的选项。 - Matthew Ruddy
1
如果您展示实际的代码,我相信可以给出更好的建议。如果您真的在寻找与当前指定需求匹配的东西:这个问题以前已经被问过(并得到了回答)。http://stackoverflow.com/questions/7003559/use-strings-to-access-potentially-large-multidimensional-arrays - hakre
也许你可以黑客(扩展)这个 Kohana 类 来满足你的要求。 - Shiplu Mokaddim
感谢@hakre提供的链接,非常有帮助。我也会看一下Kohanna类建议,听起来很有趣。谢谢你们两个! - Matthew Ruddy
5个回答

7
以下是一个遵循您的变量名称语法并解决数组成员的示例:
// String that has a value similar to an array key
$string = 'welcome["hello"]';

// initialize variable function (here on global variables store)
$vars = $varFunc($GLOBALS);

// alias variable specified by $string
$var = &$vars($string);

// set the variable
$var = 'World';

// show the variable
var_dump($welcome["hello"]); # string(5) "World"

以下是实现的代码:

/**
 * @return closure
 */
$varFunc = function (array &$store) {
    return function &($name) use (&$store)
    {
        $keys = preg_split('~("])?(\\["|$)~', $name, -1, PREG_SPLIT_NO_EMPTY);
        $var = &$store;
        foreach($keys as $key)
        {
            if (!is_array($var) || !array_key_exists($key, $var)) {
                $var[$key] = NULL;
            }
            $var = &$var[$key];
        }
        return $var;
    };
};

由于 PHP 不支持变量重载,因此您在这里受限于 PHP 的表现力,这意味着对于变量引用作为函数返回值来说不存在写入上下文,这需要额外的别名处理:

$var = &$vars($string);

如果这种方式不符合您的需求,您需要打补丁PHP。如果这仍然不可行,那么PHP并不提供您所寻找的语言特性。

另请参阅相关问题:使用字符串访问(可能很大的)多维数组


有没有一种不使用匿名函数的类似方法来实现这个?只是为了向后兼容支持。如果这是一个愚蠢的问题,对不起,这种 PHP 对我来说是新的(匿名函数、在变量前使用 '&'、使用 'use')。 - Matthew Ruddy
向下兼容到哪个 PHP 版本?而且没问题,你可以使用类模拟任何闭包。 - hakre
本质上,这段代码是WordPress插件的一部分,因此我尽量遵守其当前的最低要求。我认为只要它能在PHP 5.2.4上运行,就可以了,但我知道匿名函数是在PHP 5.3中引入的。无论如何,再次感谢,我正在努力完全理解它,并希望能够获得兼容的解决方案。 - Matthew Ruddy
@MatthewRuddy:我已经搜索了(但尚未找到)另一个解释如何将带有“use”子句的匿名函数转换为对象的答案。那基本上就是你要找的代码。 - hakre
不用担心,我会尽力弄清楚的。无论如何,感谢你的解决方案。从中学到了很多。 - Matthew Ruddy

5
变量变量中的字符在字符串中被视为字面量。它们不解释字符串内部的内容。因此,$string 中的 [] 字符不被视为数组符号。而是将其视为变量名称的一部分。

执行$$string = 'thisworks';后,PHP会创建一个名为welcome["hello"]的变量,其值设置为thisworks

要打印它,请使用这种表示法:

print (${'welcome["hello"]'});

可能是一个愚蠢的问题,但我假设没有办法告诉 PHP 停止字面理解吗? - Matthew Ruddy
@MatthewRuddy 绝对不需要。你为什么这么需要它? - RReverser
这只是我一直在尝试实现的一个想法。我已经有一个可行的替代方案,但类似于我最初发布的方法可以减少很多代码行,并且稍微更有效率。我总是喜欢尝试更好的做事方式。 - Matthew Ruddy

1
不,你不能用这种方式做那件事。 或者,你可以使用引用变量来设置。
$welcomeHello = &$welcome["hello"]

然后使用

$welcomeHello = 'thisworks'

设置条目内容。
这将是设置数组项更正确且更快速的方式。

0

你可以使用 eval,虽然我不建议在生产环境中使用它,但它确实有其优点。

<?
$string = 'welcome["hello"]';
eval('$' . $string . " = 'thisworks';");

// This also works : eval("$$string = 'thisworks';");

// I could then print the array keys value like this
print( $welcome["hello"] ); // Prints 'thisworks'

2
但是不要忘记一件事。Eval 是邪恶的。 - ahmetunal
非常同意,如果使用 eval 来处理动态内容,那么很容易受到黑客攻击,他们可以在你的脚本中运行任何命令。 - Bryan
真可惜,因为这似乎是完美的解决方案(不需要添加额外的函数)。我能否使用'call_user_func'使其更安全? - Matthew Ruddy

0
你可以使用两个变量,一个用于保存引用的变量名,另一个用于保存键值。
<?php
$myArray = array('foo', 'bar', 'baz');
$varName = 'myArray';
$varKey  = 1;
echo ${$varName}[$varKey];
// will echo "bar"

关于为什么要使用花括号来解除引用$varName

为了在数组中使用变量变量,您必须解决一个歧义问题。 也就是说,如果编写$$a[1],则解析器需要知道您是要使用$a[1]作为变量,还是要使用$$a作为变量,然后从该变量中获取[1]索引。 解决这种歧义的语法是:${$a[1]}用于第一种情况,${$a}[1]用于第二种情况。

(来源来自https://www.php.net/manual/en/language.variables.variable.php


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