我想动态访问变量的值,假设我有这个数组:
$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)
什么是解决方案?
您的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数组信息的字符串转换为数组.
如果您有(或可以获取)数组名称和键到单独的变量中,则无需 eval:
$aData = array(
'test' => 123
);
$arrayname = 'aData';
$keyname = 'test';
print ${$arrayname}[$keyname]; // 123
Run Code Online (Sandbox Code Playgroud)