如何通过键名/路径访问和操作多维数组?

2022-08-30 19:06:21

我必须在PHP中实现一个 setter,它允许我指定数组(目标)的键或子键,并将名称作为点分隔键值传递。

给定以下代码:

$arr = array('a' => 1,
             'b' => array(
                 'y' => 2,
                 'x' => array('z' => 5, 'w' => 'abc')
             ),
             'c' => null);

$key = 'b.x.z';
$path = explode('.', $key);

从值 I 想要达到 的值 5$key$arr['b']['x']['z']

现在,给定一个可变值和一个不同的值(具有不同的深度)。$key$arr

如何设置 所引用的元素的值?$key

对于 getter,我写了这个代码:get()

public static function get($name, $default = null)
{
    $setting_path = explode('.', $name);
    $val = $this->settings;

    foreach ($setting_path as $key) {
        if(array_key_exists($key, $val)) {
            $val = $val[$key];
        } else {
            $val = $default;
            break;
        }
    }
    return $val;
}

编写 setter 更加困难,因为我成功地到达了正确的元素(从 ),但是我无法在原始数组中设置值,并且我不知道如何一次指定所有键。$key

我应该使用某种回溯吗?或者我可以避免它吗?


答案 1

假设已经是一个数组 via (或 add to the function),那么你可以使用引用。您需要添加一些错误检查,以防无效等(想想):$pathexplode$pathisset

$key = 'b.x.z';
$path = explode('.', $key);

吸气剂

function get($path, $array) {
    //$path = explode('.', $path); //if needed
    $temp =& $array;

    foreach($path as $key) {
        $temp =& $temp[$key];
    }
    return $temp;
}

$value = get($path, $arr); //returns NULL if the path doesn't exist

设置者/创建者

此组合将在现有数组中设置一个值,或者如果传递一个尚未定义的数组,则创建该数组。确保定义要通过引用传递:$array&$array

function set($path, &$array=array(), $value=null) {
    //$path = explode('.', $path); //if needed
    $temp =& $array;

    foreach($path as $key) {
        $temp =& $temp[$key];
    }
    $temp = $value;
}

set($path, $arr);
//or
set($path, $arr, 'some value');

解调器

这将是路径中的最后一个键:unset

function unsetter($path, &$array) {
    //$path = explode('.', $path); //if needed
    $temp =& $array;

    foreach($path as $key) {
        if(!is_array($temp[$key])) {
            unset($temp[$key]);
        } else {
            $temp =& $temp[$key];
        }
    }
}
unsetter($path, $arr);

*原始答案有一些有限的功能,我会留下,以防它们对某人有用:

二传手

确保定义要通过引用传递:$array&$array

function set(&$array, $path, $value) {
    //$path = explode('.', $path); //if needed
    $temp =& $array;

    foreach($path as $key) {
        $temp =& $temp[$key];
    }
    $temp = $value;
}

set($arr, $path, 'some value');

或者,如果您想返回更新的数组(因为我很无聊):

function set($array, $path, $value) {
    //$path = explode('.', $path); //if needed
    $temp =& $array;

    foreach($path as $key) {
        $temp =& $temp[$key];
    }
    $temp = $value;

    return $array;
}

$arr = set($arr, $path, 'some value');

造物主

如果您不想创建数组并选择性地设置值:

function create($path, $value=null) {
    //$path = explode('.', $path); //if needed
    foreach(array_reverse($path) as $key) {
        $value = array($key => $value);
    }
    return $value;
}    

$arr = create($path);    
//or
$arr = create($path, 'some value');

为了好玩

构造并计算类似给定字符串的内容:$array['b']['x']['z']b.x.z

function get($array, $path) {
    //$path = explode('.', $path); //if needed
    $path = "['" . implode("']['", $path) . "']";
    eval("\$result = \$array{$path};");

    return $result;
}

设置类似下面的内容:$array['b']['x']['z'] = 'some value';

function set(&$array, $path, $value) {
    //$path = explode('.', $path); //if needed
    $path = "['" . implode("']['", $path) . "']";
    eval("\$array{$path} = $value;");
}

取消设置类似以下内容的内容:$array['b']['x']['z']

function unsetter(&$array, $path) {
    //$path = explode('.', $path); //if needed
    $path = "['" . implode("']['", $path) . "']";
    eval("unset(\$array{$path});");
}

答案 2

我有解决方案给你不是在纯PHP中,而是使用茴香烈酒的具体数组::getNestedValue方法:

$arr = array('a' => 1,
    'b' => array(
        'y' => 2,
        'x' => array('z' => 5, 'w' => 'abc')
    ),
    'c' => null);

$key = 'b.x.z';
$path = explode('.', $key);

print_r(Arrays::getNestedValue($arr, $path));

同样,如果需要设置嵌套值,则可以使用 Arrays::setNestedValue 方法。

$arr = array('a' => 1,
    'b' => array(
        'y' => 2,
        'x' => array('z' => 5, 'w' => 'abc')
    ),
    'c' => null);

Arrays::setNestedValue($arr, array('d', 'e', 'f'), 'value');
print_r($arr);