PHP动态数组路径访问


PHP dynamic array path access

我可以很容易地写入和读取会话数组中的子数组。

$_SESSION['a']['b']['c']['value']=123;
$val=$_SESSION['a']['b']['c']['value'];

不是硬编码写入值的"位置",我希望它可以通过字符串或其他方式定义。下面的代码显然行不通,但希望能更好地解释意图。

$prefix="['a']['b']['c']";  //defined in config page, etc
$_SESSION.$prefix.['value']=123;
$val=$_SESSION.$prefix.['value'];

如何做到这一点?

PropertyAccess

有一个很好的Symfony组件可以完成这样的任务,名为PropertyAccess。你可以这样使用它:
$persons = array('a' => array('b' => 5.7));
$accessor = PropertyAccess::createPropertyAccessor();
echo $accessor->getValue($persons, '[a][b]'); // 5.7

你可以按照文档中的描述使用Composer安装它,或者直接从GitHub获取。

自定义解决方案

这是一个完整的解决方案,我真的印象深刻,它的工作…但它确实有效!检查下面的代码,assert()演示用法:

<?php
function arrayPropertyPathGet(array $arr, $path) {
    $parts = explode('.', $path);
    $ret = $arr;
    foreach($parts as $part) {
        $ret = $ret[$part];
        }
    return $ret;
    }
function arrayPropertyPathSet(array &$arr, $path, $value) {
    $parts = explode('.', $path);
    $tmp = &$arr;
    foreach($parts as $part) {
        if(!isset($tmp[$part])) { return false; }
        $tmp = &$tmp[$part];
        }
    $tmp = $value;
    return true;
    }
$test = array('a' => array('b' => 'value'));
assert('value' === arrayPropertyPathGet($test, 'a.b'));
assert(true === arrayPropertyPathSet($test, 'a.b', 'other'));
assert('other' === arrayPropertyPathGet($test, 'a.b'));

边注

作为一个理论边注(不要将其用于学习目的之外的任何事情),您可以尝试使用eval(),例如:

eval("$value = $persons['a']['b']");

我以前也遇到过同样的问题,因为我没有找到任何解决方案,所以我自己做了一个,如果这对你有帮助的话(只是有趣的部分):

class ArrayAccessor {
    private $prefix;
    function setPrefix() {
        $this->prefix = array();
        for ($i = 0; $i < func_num_args(); ++$i) {
            $this->prefix[] =  func_get_arg($i);
        }
    }
    function getFromPrefix(array $array) {
        $tmp_array = $array;
        foreach ($this->prefix as $pre) {
            if (isset ($tmp_array[$pre])) {
                $tmp_array = $tmp_array[$pre];
            } else {
                return null;
            }
        } 
        return $tmp_array;
    }
}

$Access = new ArrayAccessor();
$Access->setPrefix('Hi', 'Toto');
$MyTestArray['Hi']['Toto'] = 'Works';
var_dump ($Access->getFromPrefix($MyTestArray));
$Access->setPrefix('Hi');
var_dump ($Access->getFromPrefix($MyTestArray));
$Access->setPrefix('No');
var_dump ($Access->getFromPrefix($MyTestArray));
结果:

string(5) "Works"
array(1) {
  ["Toto"]=>
  string(5) "Works"
}
NULL