0

Here is my precode...

$keys = array('a', 'b', 'c', 'd');
$number = 10;

And here is my code...

eval('$array[\''.implode('\'][\'',$keys).'\'] = $number;');

Using this, I get the following result...

Array (
    [a] => Array
        (
            [b] => Array
                (
                    [c] => Array
                        (
                            [d] => 10
                        )
                )
        )
)

Now, the problem is that this is the exact result I want, but I don't want to use eval().

As input to my code, I have a list of keys and a number. The number should be set to the value of the keys array being used to generate child-based keys for a certain array $array.

Is there a different way that I can achieve this? I don't want to overwrite the keys/numbers with new values as the code works - eval() preserves this already, so my new code should do the same.

hakre
  • 193,403
  • 52
  • 435
  • 836
onassar
  • 3,313
  • 7
  • 36
  • 58
  • There is a point where I have to ask why in the world you're doing this before I'll answer the question. Why would you want this structure? And is having such a rigid structure actually damaging your project? Surely there must be better storage methods in existence? – Chuck Vose Dec 29 '09 at 16:10
  • i'd have to spend about an hour writing up the full explanation of what unique situation has arisen for this requirement. sorry. – onassar Dec 29 '09 at 16:28

3 Answers3

3

Please note that the code below (which you evaluate) will generate a warning, and will therefore not work on projects with error reporting up to the max:

$array = array();
$array['a']['b'] = 42; // $array['a'] is not an array... yet

Since you're using PHP 5, you can work with references to manipulate your array while traversing the branch of your tree that you wish to modify.

$current = & $array;

foreach ($keys as $key):

  if (!isset($current[$key]) || !is_array($current[$key]))
    $current[$key] = array();

  $current = & $current[$key];

endforeach;

$current = $value;

Edit: corrected for avoiding warnings and conflicts.

Victor Nicollet
  • 24,361
  • 4
  • 58
  • 89
  • So why doesn't it throw an error on the second round where you effectively set `$array['a'] = $array['b']` since `a` is not an array yet either. Anyway, +1 since this works great and is way shorter than my answer. – Doug Neiner Dec 29 '09 at 16:24
  • 1
    firstly, what error does it generate? i have my reporting up the max, including deprecation warnings, and i dont see anything. your code works for cases where array is empty or with keys that aren't a potential conflict. but if the array looks like this: array('a' => 'b') and the keys looks like this array('a', 'orange') I get: Fatal error: Cannot create references to/from string offsets nor overloaded objects in ... – onassar Dec 29 '09 at 16:27
1

Here is a full code example showing how it would work. Whats important is that you use a reference to the array so you can modify it:

<?php
    $keys = array('a', 'b', 'c', 'd'); 
    $number = 10;

    $org_array = array(
        "a" => "string",
        "z" => array( "k" => false)
      );

    function write_to_array(&$array, $keys, $number){
      $key = array_shift($keys);
      if(!is_array($array[$key])) $array[$key] = array();
      if(!empty($keys)){
        write_to_array($array[$key], $keys, $number);
      } else {
        $array[$key] = $number;
      }
    }

    write_to_array($org_array, $keys, $number);

    print_r($org_array);
?>
Doug Neiner
  • 65,509
  • 13
  • 109
  • 118
  • this ones the closest, but again, doesn't work for the case where the array is: array('a' => 'meow') and the keys array is: array('a', 'b', 'c'). I get a Fatal error: Only variables can be passed by reference... – onassar Dec 29 '09 at 16:36
  • @onassar I misunderstood what you meant by previous values. I updated two parts in the code, the `$org_array['a']` is now set to a string to test, and I changed the `isset` test to an `is_array` test. Now if the key exists as something other than an array is is overwritten vs. extended. – Doug Neiner Dec 29 '09 at 16:47
  • follow up: what about this case for deletion: eval('unset($array[\''.implode('\'][\'',$keys).'\']);'); ? – onassar Dec 29 '09 at 23:09
1
function deepmagic($levels, $value)
{
    if(count($levels) > 0)
    {
        return array($levels[0] => deepmagic(array_slice($levels, 1),
            $value));
    }
    else
    {
        return $value;
    }
}

$a = deepmagic(Array('a', 'b', 'c', 'd'), 10);

var_dump($a);

Output:

array(1) {
  ["a"]=>
  array(1) {
    ["b"]=>
    array(1) {
      ["c"]=>
      array(1) {
        ["d"]=>
        int(10)
      }
    }
  }
}
Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358