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

发布于 2024-09-04 04:56:01 字数 673 浏览 3 评论 0原文

我目前正在优化一个 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});
        } elseif (is_array($obj) && ctype_upper($key)) {
           $obj[strtolower($key)] = $element;
           unset($obj[$key]);
        }
    }
    return $obj;
}

大部分时间都花在递归调用上(这在 PHP 中相当慢),但是我没有看到任何方法将其转换为循环。我该怎么做?

I am currently optimizing a PHP application and found one function being called around 10-20k times, so I'd thought I'd start optimization there:

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});
        } elseif (is_array($obj) && ctype_upper($key)) {
           $obj[strtolower($key)] = $element;
           unset($obj[$key]);
        }
    }
    return $obj;
}

Most of the time is spent in recursive calls (which are quite slow in PHP), but I don't see any way to convert it to a loop. How can I do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

过气美图社 2024-09-11 04:56:01

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

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;
}
扮仙女 2024-09-11 04:56:01

您可能还想查找 array_change_key_case()

对于对象,您可以执行以下操作:

($obj)array_change_key_case((arr)$o)

You might also want to lookup array_change_key_case().

For objects, you can do:

($obj)array_change_key_case((arr)$o)

海风掠过北极光 2024-09-11 04:56:01

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

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

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;
    }
}
森林散布 2024-09-11 04:56:01

这里是一个使用 lambda 的例子:

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

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

here a example using lambda:

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

    foreach ($array as $key => $row)
        if (is_array($row))
             $multiArrayChangeKeyCase($array[$key]);
};
北斗星光 2024-09-11 04:56:01
array_combine(array_map("strtolower", array_keys($a)), array_values($a))
array_combine(array_map("strtolower", array_keys($a)), array_values($a))
∞梦里开花 2024-09-11 04:56:01

对旧线程的一些迟到的响应,但是,有一个本机函数可以执行此操作,您可以沿着这些线路将其包装起来。

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

A some what late response to a old thread but, there's a native function that does this, you could wrap it up something along these lines.

function setKeyCasing($thing, $case = CASE_LOWER) {
    return array_change_key_case((array) $thing, $case);
}
唯憾梦倾城 2024-09-11 04:56:01

这是一个递归函数,它通过引用进行修改以替换可能包含任何嵌套数组或对象的数组或对象结构中的所有键/属性。它会为每个级别创建一个副本,并在完成更改所有键后覆盖该级别。

代码:(演示

function allKeysToLower(array|object &$data): void
{
    $type = gettype($data);
    foreach ($data as $k => &$v) {
        if (is_array($v) || is_object($v)) {
            (__FUNCTION__)($v);  // go to deeper level
        }
        if (is_string($k)) {
            $k = strtolower($k);  // mutate the key
        }
        switch ($type) {
            case 'object':
                $new ??= (object) [];  // create object if not created, to allow population
                $new->{$k} = $v;  // add property to object
                break;
            case 'array':
                $new[$k] = $v;  // add element to array
        }
    }
    $data = $new ?? $data;  // fallback to empty $data if loop not entered
}

allKeysToLower($test);
var_export($test);

Here is a recursive function which modifies by reference to replace all keys/properties in an array or object structure that may contain any nested arrays or objects. It makes a copy of each level and overwrites the level after it is finished changing all keys.

Code: (Demo)

function allKeysToLower(array|object &$data): void
{
    $type = gettype($data);
    foreach ($data as $k => &$v) {
        if (is_array($v) || is_object($v)) {
            (__FUNCTION__)($v);  // go to deeper level
        }
        if (is_string($k)) {
            $k = strtolower($k);  // mutate the key
        }
        switch ($type) {
            case 'object':
                $new ??= (object) [];  // create object if not created, to allow population
                $new->{$k} = $v;  // add property to object
                break;
            case 'array':
                $new[$k] = $v;  // add element to array
        }
    }
    $data = $new ?? $data;  // fallback to empty $data if loop not entered
}

allKeysToLower($test);
var_export($test);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文