访问多维数组中任意深度的键

3
如果我有一个包含['key1', 'key2', 'key3']的数组,是否有任何方法将其映射到一个$array['key1']['key2']['key3']的数组中,而不使用循环或eval()?
数组示例:
$var = [
    'key1' => [
        'subkey1' => [
            'finalkey' => 'value',
        ],
        'subkey' => [
            'otherkey' => 'value',
        ],
    ],
    'key2' => 'blah'
];

然后我有一个像这样的数组:

$keys = ['key1', 'subkey1', 'finalkey'] 

或者
$keys = ['key1', 'subkey']

我认为你的概念可能是错误的。 - Mike
你怎么能在没有循环的情况下迭代数组呢? - user142162
2
不推荐使用eval()。如果您依赖它,很可能存在另一种不使用eval()的方式来实现相同的事情。 - Mike
1
@Rogue Coder,不“使用循环”似乎是一个愚蠢的限制。PHP函数调用速度较慢。(例如,Tim的递归解决方案几乎比我在PHP 5.4上提供的迭代解决方案慢了一倍)。 - Matthew
@Matthew 谢谢,我打算继续使用我现在拥有的循环解决方案(基本上与您发布的相同)。我只是想知道是否还有其他解决方案。 - Brandon
显示剩余3条评论
3个回答

5
function array_find($needle, &$haystack)
{
    $current = array_shift($needle);
    if(!isset($haystack[$current]))
    {
        return null;
    }
    if(!is_array($haystack[$current]))
    {
        return $haystack[$current];
    }
    return array_find($needle, $haystack[$current]);
}

为什么要通过引用传递 $haystack - Matthew
@Matthew:为避免不必要的数组复制。 - user142162
如果您不修改数组,PHP 不应该制作任何副本。例如,$a = [range(0,100000)]; $b = $a[0] 不会制作副本。据我所知,您的程序也不应该制作副本,但 PHP 有时仍会让我感到惊讶... - Matthew
@nickb,哪个函数?PHP只有在修改数组时才会复制。请参见http://codepad.org/hcngGubU。无论引用的数量如何,都将使用相同数量的内存。如果发生了复制,那么非引用版本的最大内存应该随着50次复制而飙升。在PHP中,引用通常是无用的,除非您需要将数据写入别名。 - Matthew
除了用户评论之外,它并没有被经常提及。这里有一个描述ZE的地方:http://php.net/manual/en/internals2.variables.intro.php。 - Matthew
显示剩余2条评论

2
未经测试,来自于对不同问题的类似答案
function get_value($dest, $path)
{
  # allow for string paths of a/b/c
  if (!is_array($path)) $path = explode('/', $path);

  $a = $dest;
  foreach ($path as $p)
  {
    if (!is_array($a)) return null;
    $a = $a[$p];
  }

  return $a;
}

这应该比递归解决方案表现更好。

2

我针对我的个人框架提出了以下非递归方法:

function Value($data, $key = null, $default = false)
{
    if (isset($key) === true)
    {
        if (is_array($key) !== true)
        {
            $key = explode('.', $key);
        }

        foreach ((array) $key as $value)
        {
            $data = (is_object($data) === true) ? get_object_vars($data) : $data;

            if ((is_array($data) !== true) || (array_key_exists($value, $data) !== true))
            {
                return $default;
            }

            $data = $data[$value];
        }
    }

    return $data;
}

使用方法:

var_dump(Value($array, 'key1.subkey1.finalkey')); // or
var_dump(Value($array, array('key1', 'subkey1', 'finalkey')));

如果去掉对象和默认值支持以及其他检查,它可以进一步简化。


值得注意的是,像这样做比直接访问键慢100倍以上。$array['a']['b']['c']['d']Value($array, 'a.b.c.d')相比。如果你在常见项(如配置值)上依赖于此,那么在一个页面中可能有80个查找,导致额外0.020秒的成本(大约与数据库查询的成本相同)。 - Xeoncross
@Xeoncross:嗨,David!这是一个快速基准测试(http://codepad.org/cRbdxTyg),我使用`('a','b','c','d')`数组符号平均慢了10倍。 - Alix Axel

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