PHP动态访问变量值

nab*_*zan 5 php variables

我想动态访问变量的值,假设我有这个数组:

$aData = array(
  'test' => 123
);
Run Code Online (Sandbox Code Playgroud)

打印test 键值的标准方法是:

print $aData['test'];
Run Code Online (Sandbox Code Playgroud)

但是,如果我必须使用变量的字符串表示(用于动态目的)

$sItem = '$aData[\'test\']';
Run Code Online (Sandbox Code Playgroud)

我怎样才能实现打印aData 命名test?以下提供的示例都不起作用

print $$sItem;
print eval($sItem);
Run Code Online (Sandbox Code Playgroud)

什么是解决方案?

hak*_*kre 6

您的eval示例缺少返回值:

print eval("return $sItem;");
Run Code Online (Sandbox Code Playgroud)

应该这样做:

$aData['test'] = 'foo';

$sItem = '$aData[\'test\']';

print eval("return $sItem;"); # foo
Run Code Online (Sandbox Code Playgroud)

但是不建议正常使用eval.因为eval是邪恶的,你可以带着它进入地狱的厨房.

而只是解析字符串并返回值:

$aData['test'] = 'foo';

$sItem = '$aData[\'test\']';

$r = sscanf($sItem, '$%[a-zA-Z][\'%[a-zA-Z]\']', $vName, $vKey);
if ($r === 2)
{
    $result = ${$vName}[$vKey];
}
else
{
    $result = NULL;
}

print $result; # foo
Run Code Online (Sandbox Code Playgroud)

这也可以通过其他形式的正则表达式来完成.

由于您的语法非常接近PHP,实际上是它的一个子集,如果您想在使用eval之前验证输入,可以使用一些替代方法.该方法是检查PHP令牌并仅允许子集.这不验证字符串(例如语法和实际设置的变量)但是更严格:

function validate_tokens($str, array $valid)
{
    $vchk = array_flip($valid);
    $tokens = token_get_all(sprintf('<?php %s', $str));
    array_shift($tokens);
    foreach($tokens as $token)
        if (!isset($vchk[$token])) return false;
    return true;
}
Run Code Online (Sandbox Code Playgroud)

您只需为该函数提供一组有效标记即可.那些是PHP令牌,在你的情况下是:

T_LNUMBER (305) (probably)
T_VARIABLE (309)
T_CONSTANT_ENCAPSED_STRING (315)
Run Code Online (Sandbox Code Playgroud)

然后你可以使用它,它也适用于更复杂的键:

$aData['test'] = 'foo';
$aData['te\\\'[]st']['more'] = 'bar';

$sItem = '$aData[\'test\']';
$vValue = NULL;
if (validate_tokens($sItem, array(309, 315, '[', ']')))
{
    $vValue = eval("return $sItem;");
}
Run Code Online (Sandbox Code Playgroud)

我在问题的另一个答案中使用了这个,可靠地将包含PHP数组信息的字符串转换为数组.


Boa*_*ann 5

如果您有(或可以获取)数组名称和键到单独的变量中,则无需 eval:

$aData = array(
  'test' => 123
);

$arrayname = 'aData';
$keyname = 'test';

print ${$arrayname}[$keyname]; // 123
Run Code Online (Sandbox Code Playgroud)