tags:

views:

50

answers:

4

I have an array with configuration tree:

$cfg = array('global' => array(
    'project'       => 'foo',
    'base_url'      => '/path/',
    'charset'       => 'utf-8',
    'timezone'      => 'Europe/Lisbon',
    'environment'   => 'development'),
    //...
);

I need to insert an element into the tree (or possibly change it) given strings such as "global:project" and "bar" where first specifies a path to an element and second its value. So the value 'foo' in $cfg['global']['project'] would become 'bar'.

Here is the function I need:

function set_cfg($path, $value)
{ /* Alter $cfg with the given settings */ }

So I start by exploding the path string with ':' and have an array with path keys:

$path = explode(':', $path)

What's next? How can I define (recursively?) an operation of keys insertion into the $cfg array?

+2  A: 

Add the array as a reference argument to the function, then recurse, passing in the slice of the array you want to further examine. When you get to the end, stop (and assign the value to the key).

Ignacio Vazquez-Abrams
-1 I see no reason to use recursion here. The weak references PHP implements are perfectly suited for this task.
nikic
A: 

I would build a loop that goes through each element in the path when at the end assign the value.

The following code deals with updating as requested but it doesn't yet deal with empty nodes along the path if that could happen(most likely) make sure to do a check in the loop and create the new arrays as needed.

$node=$cfg;
$i=0;
while($i<count($path)-1)
{
  $node = $node[$path[$i]];
  i++;
}

$node[$path[$i]]=$value;
Jeff Beck
@Jeff Beck: OKay, but `$i++`?
Rizo
Yep good catch.
Jeff Beck
+1  A: 

This may sound crazy but something like this:

eval("\$cfg['".str_replace(':', "']['", $path)."'] = ".var_export($value, true).';');
orvado
-1 Avoid eval if you can - and here you definitely can!
nikic
@orvado: I really liked it, but I will not use it! ;)
Rizo
+1 for creativity (although it created something ugly)
Gordon
+1  A: 
function set_cfg($path, $value) {
    $path = explode(':', $path);
    $current = &$GLOBALS['cfg']; // variable is global, so get from $GLOBALS
    foreach ($path as $part) {
        $current = &$current[$part];
    }
    $current = $value;
}

If you can be sure that there will be always only two levels of configuration you may instead use:

function set_cfg($path, $value) {
    list($first, $second) = explode(':', $path, 2);
    $GLOBALS['cfg'][$first][$second] = $value;
}
nikic
Perfect! Thanks!
Rizo
No, there may be more than two levels, but thank you, anyway!
Rizo