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