2

I am trying to create a multi-dimensional array whose parts are determined by a string. I'm using . as the delimiter, and each part (except for the last) should be an array
ex:

config.debug.router.strictMode = true

I want the same results as if I were to type:

$arr = array('config' => array('debug' => array('router' => array('strictMode' => true))));

This problem's really got me going in circles, any help is appreciated. Thanks!

Gumbo
  • 643,351
  • 109
  • 780
  • 844
Steven Mercatante
  • 24,757
  • 9
  • 65
  • 109

5 Answers5

4

I say split everything up, start with the value, and work backwards from there, each time through, wrapping what you have inside another array. Like so:

$s = 'config.debug.router.strictMode = true';
list($parts, $value) = explode(' = ', $s);

$parts = explode('.', $parts);
while($parts) {
   $value = array(array_pop($parts) => $value);
}

print_r($parts);

Definitely rewrite it so it has error checking.

JasonWoof
  • 4,176
  • 1
  • 19
  • 28
  • This works nicely, but I'm curious as to the possible errors I should be checking for. – Steven Mercatante Sep 13 '09 at 06:57
  • This looks like it breaks if you want to parse/store more than one line. – timdev Sep 13 '09 at 07:08
  • Arms: It will break if the line doesn't have " = " in it for example. Basically, lines that don't match the syntax exactly cause my script to throw php errors. You'll want to make it much more forgiving (like not requiring the spaces next to the equals) and handle errors in some meaningful way, instead of php errors, like "invalid argument to foreach()". – JasonWoof Sep 13 '09 at 07:13
  • This should be marked as the best answer! Simple and elegant! – Marcio Mazzucato Oct 08 '14 at 12:35
4

Let’s assume we already have the key and value in $key and $val, then you could do this:

$key = 'config.debug.router.strictMode';
$val = true;
$path = explode('.', $key);

Builing the array from left to right:

$arr = array();
$tmp = &$arr;
foreach ($path as $segment) {
    $tmp[$segment] = array();
    $tmp = &$tmp[$segment];
}
$tmp = $val;

And from right to left:

$arr = array();
$tmp = $val;
while ($segment = array_pop($path)) {
    $tmp = array($segment => $tmp);
}
$arr = $tmp;
Gumbo
  • 643,351
  • 109
  • 780
  • 844
1

Gumbo's answer looks good.

However, it looks like you want to parse a typical .ini file.

Consider using library code instead of rolling your own.

For instance, Zend_Config handles this kind of thing nicely.

timdev
  • 61,857
  • 6
  • 82
  • 92
1

I really like JasonWolf answer to this.

As to the possible errors: yes, but he supplied a great idea, now it is up to the reader to make it bullet proof.

My need was a bit more basic: from a delimited list, create a MD array. I slightly modified his code to give me just that. This version will give you an array with or without a define string or even a string without the delimiter.

I hope someone can make this even better.

$parts = "config.debug.router.strictMode";

$parts = explode(".", $parts);

$value = null;

while($parts) {
  $value = array(array_pop($parts) => $value);
}


print_r($value);
Old Man Walter
  • 629
  • 2
  • 7
  • 16
0
// The attribute to the right of the equals sign
$rightOfEquals = true; 

$leftOfEquals = "config.debug.router.strictMode";

// Array of identifiers
$identifiers = explode(".", $leftOfEquals);

// How many 'identifiers' we have
$numIdentifiers = count($identifiers);


// Iterate through each identifier backwards
// We do this backwards because we want the "innermost" array element
// to be defined first.
for ($i = ($numIdentifiers - 1); $i  >=0; $i--)
{

   // If we are looking at the "last" identifier, then we know what its
   // value is. It is the thing directly to the right of the equals sign.
   if ($i == ($numIdentifiers - 1)) 
   {   
      $a = array($identifiers[$i] => $rightOfEquals);
   }   
   // Otherwise, we recursively append our new attribute to the beginning of the array.
   else
   {   
      $a = array($identifiers[$i] => $a);
   }   

}

print_r($a);
poundifdef
  • 18,726
  • 23
  • 95
  • 134