我可以快速发现两个不同的任务。一个是将字符串转换为驼峰格式,另一个是映射多维数组的键。这些任务互不相关,因此最好将它们实现为单独的函数。
让我们从一个高阶函数
mapArrayKeys
开始。它将接受一个映射函数,并将该函数应用于数组的每个键,生成一个新的数组。我们必须期望映射函数是单射(一对一)。
function mapArrayKeys(callable $f, array $xs) {
$out = array();
foreach ($xs as $key => $value) {
$out[$f($key)] = is_array($value) ? mapArrayKeys($f, $value) : $value;
}
return $out;
}
有一些琐碎的细节我认为并不重要。如果您不想对参数进行类型提示,那没问题。也许您更喜欢用if/then/else代替三元运算符,那也可以。重要的是,使用mapArrayKeys
,您可以将任何(单射)映射函数应用于数组键。
第二个任务是将字符串转换为驼峰式大小写。您可以使用PCRE函数来实现这一点,也可以用explode
进行拆分。
function underToCamel($str) {
return lcfirst(implode('', array_map('ucfirst', explode('_', $str))));
}
现在这两个函数可以配合使用,以实现将数组键从下划线格式转换为驼峰格式的总体目标。
mapArrayKeys('underToCamel', array('foo_bar' => array ('baz_qux' => 0)));
关于单射性的说明。函数
underToCamel
不一定是单射的,因此您需要特别注意。您必须假设对于所有
x_y
和所有
xY
(其中Y是y的大写版本),恰好有一个
x_y
、
xY
、
x_Y
是下划线格式(同样适用于更多下划线)。
例如,
underToCamel("foo_bar") == "fooBar"
和
underToCamel("fooBar") == "fooBar"
以及
underToCamel("foo_Bar") == "fooBar"
,因此只有一个可以是有效的下划线格式。
嵌套函数的可读性
这是针对
luqo33的评论而作出的回应。
引用:
“我所指的‘过于复杂’(至少在我的看法中)是指该解决方案使用了许多嵌套函数(例如在underToCamel中调用了四个函数,全部嵌套——阻碍了可读性)。”
涉及的代码行如下。
lcfirst(implode('', array_map('ucfirst', explode('_', $str))));
我认为这篇文章是可读的。我承认这种风格对于PHP来说并不典型,我觉得这也是为什么PHP读者可能会感到不适的原因。
首先需要注意的是,嵌套函数并不像你想象的那样不正常。考虑一个数学表达式。
(-$b + sqrt($b*$b - 4*$a*$c)) / (2*$a)
这是一个使用了许多嵌套函数的表达式:
+, -, *, /
。如果你假装自己没有把BEDMAS(或相当于其的规则)潜移默化地学会,那么这实际上是一个很复杂的表达式——有一些隐含的规则,你下意识地应用它们来知道首先要做括号里的运算,然后再进行乘除等操作。这些规则似乎并不复杂,因为你已经学会了如何阅读这样的表达式,并且它已经成为了你的技能库的一部分。对于像我使用的表达式这样的表达式也是如此。
我可以重写表达式,使每行只使用一个函数。
$a = explode('_', $str);
$b = array_map('ucfirst', $a);
$c = implode('', $b);
$d = lcfirst($c);
现在执行顺序是从上到下读取。我也可以将其编写为从下到上读取。
lcfirst(
implode('',
array_map('ucfirst',
explode('_',
$str
))));
最后,我可以将其编写为从右向左或由内向外阅读(如果考虑括号的话),这是它最初的书写方式。
lcfirst(implode('', array_map('ucfirst', explode('_', $str))));
所有这些版本都使用了一个简单的模式,称为“函数组合”,这也是它易于阅读和理解的另一个原因。使用函数组合,您可以构建一系列函数,其中每个函数从前一个函数的输出中获取输入。
为了解释这种情况,按从左到右的顺序,我的函数序列是
explode '_', array_map 'ucfirst', implode '', lcfirst
。它的工作方式可以清楚地从使用变量
$a
到
$d
的版本中看出。您将某些内容放入
explode '_'
中,然后将结果传递给
array_map 'ucfirst'
,然后传递给
implode ''
,最后传递给
lcfirst
。您可以将其视为管道、装配线或类似的东西。
'/_([^_])/',
考虑到了数组键包含字母和下划线以外的字符的情况 - 这当然涉及到第三个选项 :)。 - luqo33