基于字符串引用多维数组的元素,无需 eval

Referencing a multidimensional array's elements based on a string without eval

提问人:Ultimater 提问时间:10/31/2012 更新时间:10/17/2013 访问量:470

问:

好的,我正在处理一个大型多维数组,其中包含的信息比我需要的要多,我想遍历它以过滤我感兴趣的数据。可悲的是,这个多维数组是动态生成的,并不总是包含我想要的数据,所以我必须使用这样的逻辑:

if(isset($ar['b']['ba']['baa'])){
echo '<h3>'.$ar['b']['ba']['baa'].'</h3>';
}
if(isset($ar['b']['ba']['baba'])){
echo '<h3>'.$ar['b']['ba']['baba'].'</h3>';
}
if(isset($ar['b']['ba']['babb'])){
echo '<h3>'.$ar['b']['ba']['babb'].'</h3>';
}

上面的效果很好,但看起来有点凌乱,所以我将上面的内容转换为:

$refAr=array();
$refAr[]='b->ba->baa';//3
$refAr[]='b->ba->bab->baba';//4
$refAr[]='b->ba->bab->babb';//5

上面看起来更加漂亮和整洁,是我想控制脚本的方式,以防将来我需要引用不同的键。我遇到的问题是尝试使用上述格式来实际引用数组。我以为变量会起作用,但显然它失败了。我第二次尝试使用 eval 成功了,但我对我的解决方案不是很满意。这就是我需要你们进来的地方,有没有更好的方法?以下是我的尝试:

<?php

$ar=array(
    'a'=>array('aa'=>1,'ab'=>2),
    'b'=>array(
        'ba'=>array('baa'=>3,'bab'=>array('baba'=>4,'babb'=>5),'bac'=>array('baca'=>6,'bacb'=>7)),
    )
);


$refAr=array();
$refAr[]='b->ba->baa';//3
$refAr[]='b->ba->bab->baba';//4
$refAr[]='b->ba->bab->babb';//5
foreach($refAr as $ref)
{
    $r=explode('->',$ref);
    $r="\$ar['".implode("']['",$r)."']";
    echo '<h1>'.$r.'</h1>';
    echo '<h3>'.$$r.'</h3>';//undefined
    eval('$t='.$r.';');
    echo "<h3>$t</h3>";//works but uses eval, is there a better way?

}
PHP 多维数组 eval 变量变量

评论


答:

1赞 Baba 10/31/2012 #1

你可以试试

$ar = array();
$ar['b']['ba']['baa'] = 3;
$ar['b']['ba']['bab']['baba'] = 4;
$ar['b']['ba']['bab']['babb'] = 5;

$refAr = array();
$refAr[] = 'b->ba->baa'; // 3
$refAr[] = 'b->ba->bab->baba'; // 4
$refAr[] = 'b->ba->bab->babb'; // 5

foreach ( $refAr as $ref ) {
    $t = $ar;
    foreach ( explode("->", $ref) as $v ) {
        if (!isset($t[$v]))
            break;
        $t = $t[$v];
    }
    is_array($t) and $t = null;
    echo "<h3>$t</h3>";
}

输出

3

4

5

评论

0赞 HenchHacker 10/31/2012
不错,除了 foreach 内部的 explode(“->”, $ref) - 如果它在 foreach 中与在 for 循环中相同,我不是 100%的(但我会想象它是),但爆炸不应该在 foreach 之外以防止 explode() 函数在每次迭代时被调用......><
0赞 Ultimater 10/31/2012
这有效,但它不会首先检查变量是否存在,因此如果引用无效,则当回显不存在时,它会生成警告。尝试添加:$refAr[]='b->doesnt->exist';
0赞 Asad Saeeduddin 10/31/2012
只需添加一个条件来检查 if 并中断循环,如果为 true,则不输出。array_key_exists($v,$t)
0赞 Baba 10/31/2012
@VBAssassin它创建数组的副本,只要你调用它,不管它是在里面还是在变量中,它仍然会创建一个副本。这是唯一的副本foreach
0赞 Ultimater 10/31/2012
似乎正在工作,这部分是我一直在挣扎的。你能不能让这个东西也与数组引用一起使用,用于对数组的引用,而不仅仅是字符串和数字?is_array($t)b->ba
0赞 Ultimater 10/17/2013 #2

我决定回答我自己的问题。这是我最终使用的:

<?php

//Sample PHP representation of dynamically-pulled JSON data from an untrusted source
$ar=array(
    'a'=>array('aa'=>1,'ab'=>2),
    'b'=>array(
        'ba'=>array('baa'=>3,'bab'=>array('baba'=>4,'babb'=>5),'bac'=>array('baca'=>6,'bacb'=>7)),
    )
);

//Reusable function
function resolveReference($ar,&$ref)
{
    $t = $ar;
    foreach ( explode('->',$ref) as $v )
    {
        if (!array_key_exists($v,$t)){$ref=null;return false;}
        $t = $t[$v];
    }
    $ref=$t;
    return true;
}

//The references I'm interested in but don't know if my dynamic data will contain these keys every time
$refAr=array();
$refAr[]='b->ba->baa';
$refAr[]='b->ba->bab->baba';
$refAr[]='b->ba->bab->babb';
$refAr[]='b->doesnt->exist';


foreach($refAr as $ref)
{
    echo '<h1>'.$ref.'</h1>';
    if(resolveReference($ar,$ref))
    {
        echo '<h3><span style="color:blue;">'.$ref.'</span></h3>';
    }else{
        echo '<h3><span style="color:red;">Alternative text for non-existent expected reference</span></h3>';
    }
}