[php] How to write getter/setter to access multi-level array by key names?



5 Answers

I have solution for you not in the pure PHP, but using ouzo goodies concretely Arrays::getNestedValue method:

$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));

Similarly if you need to set nested value you can use Arrays::setNestedValue method.

$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);
Question

I've to implement a setter in PHP, that allows me to specify the key, or sub key, of an array (the target), passing the name as a dot-separated-keys value.

Given the following code:

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

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

From the value of $key I want to reach the value 5 of $arr['b']['x']['z'].

Now.... given a variable value of $key and a different $arr value (with different deepness).

How can I set the value of the element pointed by $key?

For the getter get() I wrote this code:

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;
}

To write a setter is more difficult because I succeed in reaching the right element (from the $key), but I am not able to set the value in the original array and I don't know how to specify the key all at once.

Should I use some kind of backtracking? Or can I avoid it?




<?php
    $string = 'router.format';
    $array = array(
        'router' => array(
            'format' => 'xml',
        ),
    );

    $string = explode('.', $string);
    $result = $array;

    for($i = 0; $i < count($string); ++$i)
    {  
        $key = $string[$i];
        if(isset($result[$key]))
            $result = $result[$key];
        else
            break;
    }

    print_r($result);



//In your main function
public function something() {
    $settings = array(
     "age" => "25",
     "data" => array(
        "name" => "John Dewey",
        "zip_code" => "00000"
      )
    );

   $target = 'data.name';
   $input = 'Other Name'

  $new_arr = dont_know_what_to_do($target_dir, $input);

  print_r($new_arr);        
}


//Create new function
public function dont_know_what_to_do($settings, $target, $input) {
  $key = explode('.', $target)
  return $settings['data'][$key[1]] = $input;
}



Convert dot syntax like “this.that.other” to multi-dimensional array in PHP

Try this number...

function assignArrayByPath(&$arr, $path, $value, $separator='.') {
    $keys = explode($separator, $path);

    foreach ($keys as $key) {
        $arr = &$arr[$key];
    }

    $arr = $value;
}

CodePad

It will loop through the keys (delimited with . by default) to get to the final property, and then do assignment on the value.

If some of the keys aren't present, they're created.




I would suggest using dflydev/dot-access-data.

If you're not familiar with using Composer, head over to https://getcomposer.org/ for an introduction so that you can download and autoload the package as as dependency for your project.

Once you have the package, you can load a multi-dimensional array into a Data object:

use Dflydev\DotAccessData\Data;

$data = new Data(array(
  's1' => array(
    't1' => array(
      'column' => array(
        '1' => 'size:33%',
      ),
    ),
  ),
);

And access the values using dot notation:

$size = $username = $data->get('s1.t1.column.1');



Dynamically modify associative array values in php

Here is the dynamic set funciton, you can use it set any depth. Demo here for you question.

function set($settings, $target_directory, $new_value)
{
  $array = explode('.', $target_directory);
  $ref = &$settings;
  while($v = current($array))
  {
    $ref = &$ref[$v];
    next($array);
  }
  $ref = $new_value;
  return $settings;
}



Related



Tags

php php   arrays