2

I'm creating JSON encoded data from PHP arrays that can be two or three levels deep, that look something like this:

[grandParent] => Array (
                       [parent] => Array (
                                         [child] => myValue 
                                      )
                    )

The method I have, which is simply to create the nested array manually in the code requires me to use my 'setOption' function (which handles the encoding later) by typing out some horrible nested arrays, however:

$option = setOption("grandParent",array("parent"=>array("child"=>"myValue")));

I wanted to be able to get the same result by using similar notation to javascript in this instance, because I'm going to be setting many options in many pages and the above just isn't very readable, especially when the nested arrays contain multiple keys - whereas being able to do this would make much more sense:

$option = setOption("grandParent.parent.child","myValue");

Can anyone suggest a way to be able to create the multidimensional array by splitting the string on the '.' so that I can json_encode() it into a nested object?

(the setOption function purpose is to collect all of the options together into one large, nested PHP array before encoding them all in one go later, so that's where the solution would go)

EDIT: I realise I could do this in the code:

$options['grandparent']['parent']['child'] = "myValue1";
$options['grandparent']['parent']['child2'] = "myValue2";
$options['grandparent']['parent']['child3'] = "myValue3";

Which may be simpler; but a suggestion would still rock (as i'm using it as part of a wider object, so its $obj->setOption(key,value);

Codecraft
  • 8,291
  • 4
  • 28
  • 45

4 Answers4

9

This ought to populate the sub-arrays for you if they haven't already been created and set keys accordingly (codepad here):

function set_opt(&$array_ptr, $key, $value) {

  $keys = explode('.', $key);

  // extract the last key
  $last_key = array_pop($keys);

  // walk/build the array to the specified key
  while ($arr_key = array_shift($keys)) {
    if (!array_key_exists($arr_key, $array_ptr)) {
      $array_ptr[$arr_key] = array();
    }
    $array_ptr = &$array_ptr[$arr_key];
  }

  // set the final key
  $array_ptr[$last_key] = $value;
}

Call it like so:

$opt_array = array();
$key = 'grandParent.parent.child';

set_opt($opt_array, $key, 'foobar');

print_r($opt_array);

In keeping with your edits, you'll probably want to adapt this to use an array within your class...but hopefully this provides a place to start!

rjz
  • 16,182
  • 3
  • 36
  • 35
  • Results in a bunch of errors and warnings about 'Call-time pass-by-reference has been deprecated' as well as undefined variables and bad arguments BUT does appear to produce whats needed at the end... at the moment it's the closest solution. – Codecraft May 09 '12 at 15:58
  • I moved that reference from the function definition to the call...please feel free to suggest other bugs/fixes as you run across them! – rjz May 09 '12 at 16:03
  • It needs to be function set_opt(&array_ptr, ... and call it without the &, that gets rid of the errors! – Codecraft May 09 '12 at 16:06
  • Perfect, I'm using it in an OO context so I made some tweaks so that you also don't have to keep referencing the object you're updating too: http://codepad.org/t7KdNMwV – Codecraft May 09 '12 at 16:17
  • No longer a valid answer for PHP 5.4+ since it will error out. http://php.net/manual/en/language.references.pass.php – Du3 May 01 '15 at 17:13
0

What about $option = setOption("grandParent", { parent:{ child:"myValue" } });?

Doing $options['grandparent']['parent']['child'] will produce an error if $options['grandparent']['parent'] was not set before.

Rémi Breton
  • 4,209
  • 2
  • 22
  • 34
  • I'm worried for code readability (and the ease of typing/editing it), and that's going to be no easier when there are lots of sub keys nested into the array. Also, when all calls to setOption have been finished, it should have built a PHP array which is then just passed once through json_encode() - so what you have there doesn't look like it'd work. – Codecraft May 09 '12 at 15:48
0

The OO version of the accepted answer (http://codepad.org/t7KdNMwV)

  $object = new myClass();
  $object->setOption("mySetting.mySettingsChild.mySettingsGrandChild","foobar");
  echo "<pre>".print_r($object->options,true)."</pre>";

  class myClass {

     function __construct() {
        $this->setOption("grandparent.parent.child","someDefault");
     }

    function _setOption(&$array_ptr, $key, $value) {

        $keys = explode('.', $key);

        $last_key = array_pop($keys);

        while ($arr_key = array_shift($keys)) {
            if (!array_key_exists($arr_key, $array_ptr)) {
                $array_ptr[$arr_key] = array();
            }
            $array_ptr = &$array_ptr[$arr_key];
        }

        $array_ptr[$last_key] = $value;
    }

    function setOption($key,$value) {

        if (!isset($this->options)) {
            $this->options = array();
        }

        $this->_setOption($this->options, $key, $value);
        return true;                        
    }

  }
Codecraft
  • 8,291
  • 4
  • 28
  • 45
0

@rjz solution helped me out, tho i needed to create a array from set of keys stored in array but when it came to numerical indexes, it didnt work. For those who need to create a nested array from set of array indexes stores in array as here:

$keys = array(
    'variable_data',
    '0',
    'var_type'
);

You'll find the solution here: Php array from set of keys

Community
  • 1
  • 1
Deko
  • 1,028
  • 2
  • 15
  • 24