0

Possible Duplicate:
Check if a “run-time” multidimensional array key exists

Hi,

I have a multidimensional array. I need a function that checks if a specified key exists and if not set the value.

Let's take this array

$config['lib']['template']['engine'] = false;

A function should not update the value to true when i call with:

checkAndSetKey('lib template engine',true);
//> Checks if isset $config['lib']['template']['engine'] and if not isset $config['lib']['template']['engine'] = true;

Note that my array isn't only 3 dimensional. It should be able to check and set even with only 1 dimension:

checkAndSetKey('genericSetting',true);
//> In this considering there isn't any $c['genericSetting'] the function set the key to true;

At the moment I am using an awful eval code, I would like to hear suggest :)

To dynamically check if the key exists it could be used this code:

$array = $config;
$keys=explode(' ',$argument1);

foreach($keys as $v) { 

    if (!array_key_exists($v,$array)) {
        //> [todo!] the current key doens't exist now we should set the value
    }

    $array = &$array[$v];
}
3
  • can be useful: stackoverflow.com/questions/6088115/… It doesn't looks like good way to change settings. Commented May 22, 2011 at 15:00
  • That was my own question. And they aren't DUP because that question was only to see if it was isset not to set. Read better next time Commented May 22, 2011 at 19:46
  • i guess if jeff closes it i will say anything xD Commented May 22, 2011 at 22:28

3 Answers 3

1

With slight modification (passing array as reference argument) this should work:

function checkAndSetKey(&$arr, $keys, $value){
    $moreKeys = strpos($keys,' ');
    if($moreKeys !== FALSE){
        $currentKey = substr($keys, 0, $moreKeys);
        $keys = substr($keys, $moreKeys+1);

        if(!isset($arr[$currentKey]) || !is_array($arr[$currentKey]))
            $arr[$currentKey] = array();

        return checkAndSetKey($arr[$currentKey], $keys, $value);
    }else{
        $currentKey = $keys;
        if(!isset($arr[$currentKey]))
            $arr[$currentKey] = $value;

        return $arr[$currentKey];
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

without those big if the code would have looked beautfiul
Code should be efficient, readable and reusable - that makes it beautiful.
0

LOL actually this was just one line of code added there =/
For a moment the references confused me a bit.

Here the code :

function _c($key,$value) {
    global $c;

    $array = &$c;
    $keys = explode(' ',$key);

    $setValue = false;
    for($i=0;$i<count($keys);$i++) { 
        $v = $keys[$i];

        //> If setValue is already = true we don't need to check it again
        if (!$setValue && !array_key_exists($v,$array))
            $setValue = true;

        $array = &$array[$v];
    }

    if ($setValue)
        $array = $value;
}

//> Usage _c('lib template engine',true);

3 Comments

You may want to change foreach loop to for to iterate through all given keys. Now when you call _c('lib template engine',true); with emty $c, you will end with $c = array('lib' => true); and even calling it 3 times would not set desired key
yes there are some errors with an empty $c. I need to thing about a solution
@dev-null-dweller: edited the reply. Now based on the var $setValue will set within the right array
0

First off, its worth bearing in mind that PHP arrays are NOT multi-dimensional, they are hierarchical.

PHP already provides a method for testing if an array key exists. Wrapping this in your own code should be trivial, particularly if the number of levels in the array is fixed:

function checkAndSetKey(&$arr, $path, $default)
{
   $path=explode(' ', $path);

   if (!is_array($arr[$path[0]])) { // lib
         $arr[$path[0]]=array();
   }
   if (!is_array($arr[$path[0]][$path[1]])) { // template
         $arr[$path[0]][$path[1]]=array();
   }
   if (!array_key_exists($path[2],$arr[$path[0]][$path[1]])) { // engine
         $arr[$path[0]][$path[1]][$path[2]]=$default;
   }
   return $arr[$path[0]][$path[1]][$path[2]];
}

With a bit of though the method above could be adapted using recursion to handle an arbitrary number of levels.

1 Comment

I don't find a way in your code with recursion to make it for arbitary number