+1  A: 
array_combine(array_map("strtolower", array_keys($a)), array_values($a))
mario
Doesn't recurse, but probably a good start to speed up his code
Erik
Works with arrays, but doesn't work with objects.
tstenner
Correction: works with arrays, as long as you cast them using `(array) $a`
tstenner
+3  A: 

Foreach is using an internal copy that is then traversed. Try it without:

function keysToLower($obj)
{
    $type = (int) is_object($obj) - (int) is_array($obj);
    if ($type === 0) return $obj;
    reset($obj);
    while (($key = key($obj)) !== null)
    {
        $element = keysToLower(current($obj));
        switch ($type)
        {
        case 1:
            if (!is_int($key) && $key !== ($keyLowercase = strtolower($key)))
            {
                unset($obj->{$key});
                $key = $keyLowercase;
            }
            $obj->{$key} = $element;
            break;
        case -1:
            if (!is_int($key) && $key !== ($keyLowercase = strtolower($key)))
            {
                unset($obj[$key]);
                $key = $keyLowercase;
            }
            $obj[$key] = $element;
            break;
        }
        next($obj);
    }
    return $obj;
}

Or use references to avoid that a copy is used:

function &keysToLower(&$obj)
{
    $type = (int) is_object($obj) - (int) is_array($obj);
    if ($type === 0) return $obj;
    foreach ($obj as $key => &$val)
    {
        $element = keysToLower($val);
        switch ($type)
        {
        case 1:
            if (!is_int($key) && $key !== ($keyLowercase = strtolower($key)))
            {
                unset($obj->{$key});
                $key = $keyLowercase;
            }
            $obj->{$key} = $element;
            break;
        case -1:
            if (!is_int($key) && $key !== ($keyLowercase = strtolower($key)))
            {
                unset($obj[$key]);
                $key = $keyLowercase;
            }
            $obj[$key] = $element;
            break;
        }
    }
    return $obj;
}
Gumbo
Works fine except with nested arrays without keys every array on the second level is empty, e.g. `keysToLower(array(array(array(1,2))))` returns `array(0=>array())`
tstenner
And the `if($key !== $keyLowercase)` prevents values in an array with a lowercase key from being processed, e.g. `array('lowercase'=>array('UPPERCASE'=>1))` won't work.Inserting an `else $val=keysToLower($val);` fixes this.
tstenner
tstenner
@tstenner: Fixed it.
Gumbo
I just checked, it runs about 30% faster than my version, moving the `is_int` in the switch statement and unsetting the old key first slows it down again.
tstenner
@tstenner: Which one did you use?
Gumbo
The second with the references, I'll include it in the question.
tstenner
Creating a new object instead of unsetting the old keys speeds it up in my case.
tstenner
A: 

I assume you don't care about casting to array...

function keys_to_lower($o) {
    if (is_object($o)) {
        $o = (array)$o;
    }
    if (is_array($o)) {
        return array_map('keys_to_lower', array_change_key_case($o));
    }
    else {
        return $o;
    }
}
Oblio
I do care, but I will measure, whether doing this and recasting it back before returning will make any difference.
tstenner