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

4
  • Someone just recently asked the same question. Let's see if i can find it. Commented May 9, 2012 at 15:23
  • Found it Commented May 9, 2012 at 15:25
  • I think thats the opposite of what i'm looking for :( I want to start with the dot notation as a string, and convert into a PHP multi-dimensional array. Commented May 9, 2012 at 15:31
  • Gotcha, I was thinking the opposite. Commented May 9, 2012 at 15:34

4 Answers 4

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!

Sign up to request clarification or add additional context in comments.

5 Comments

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.
I moved that reference from the function definition to the call...please feel free to suggest other bugs/fixes as you run across them!
It needs to be function set_opt(&array_ptr, ... and call it without the &, that gets rid of the errors!
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: codepad.org/t7KdNMwV
No longer a valid answer for PHP 5.4+ since it will error out. php.net/manual/en/language.references.pass.php
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.

1 Comment

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

  }

Comments

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.