将数组/对象树的键转换为小写

时间:2010-06-05 18:07:23

标签: php performance

我目前正在优化PHP应用程序,发现一个函数被调用大约10-20k次,所以我想我会在那里开始优化:

function keysToLower($obj)
{
        if(!is_object($obj) && !is_array($obj)) return $obj;
        foreach($obj as $key=>$element)
        {
                $element=keysToLower($element);
                if(is_object($obj))
                {
                        $obj->{strtolower($key)}=$element;
                        if(!ctype_lower($key)) unset($obj->{$key});
                }
                else if(is_array($obj) && ctype_upper($key))
                {
                        $obj[strtolower($key)]=$element;
                        unset($obj[$key]);
                }
        }
        return $obj;
}

大部分时间花在递归调用上(在PHP中速度很慢),但我没有看到任何方法将其转换为循环。 你会做什么?

此版本不考虑关联数组,因为我的数据没有,但比原始版本快近10倍。大部分工作都是由Gumbo完成的,主要的加速来自于使用引用和创建新对象而不是取消设置旧密钥。

function &keysToLower(&$obj)
{
    if(is_object($obj))
    {
        $newobj = (object) array();
        foreach ($obj as $key => &$val)
            $newobj->{strtolower($key)} = keysToLower($val);
        $obj=$newobj;
    }
    else if(is_array($obj))
        foreach($obj as &$value)
            keysToLower($value);
    return $obj;
}

6 个答案:

答案 0 :(得分:5)

Foreach正在使用随后遍历的内部副本。不用尝试:

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;
}

或使用引用来避免使用副本:

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;
}

答案 1 :(得分:3)

您可能还想查找array_change_key_case()

答案 2 :(得分:2)

我假设你不关心转换为数组......

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;
    }
}

答案 3 :(得分:2)

这里使用lambda的例子:

$multiArrayChangeKeyCase = function (&$array) use (&$multiArrayChangeKeyCase) {
    $array = array_change_key_case($array);

    foreach ($array as $key => $row)
        if (is_array($row))
             $multiArrayChangeKeyCase($array[$key]);
};

答案 4 :(得分:1)

array_combine(array_map("strtolower", array_keys($a)), array_values($a))

答案 5 :(得分:0)

对旧线程有一些较晚的响应,但是有一个本机函数可以执行此操作,您可以按照以下方式将其包装起来。

function setKeyCasing($thing, $case = CASE_LOWER) {
    return array_change_key_case((array) $thing, $case);
}