views:

254

answers:

4

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!

+3  A: 

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
This works nicely, but I'm curious as to the possible errors I should be checking for.
Arms
This looks like it breaks if you want to parse/store more than one line.
timdev
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
+1  A: 

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
A: 
// 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);
rascher
+1  A: 

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