我出于好奇做了一个实验。我想看看strtolower()
和strtoupper()
之间是否存在微观差异。我预计strtolower()
在大多数小写字符串上会更快,反之亦然。我发现strtolower()
在所有情况下都较慢(尽管在你做了数百万次之前完全无关紧要。)这是我的考验。
$string = 'hello world';
$start_time = microtime();
for ($i = 0; $i < 10000000; $i++) {
strtolower($string);
}
$timed = microtime() - $start_time;
echo 'strtolower ' . $string . ' - ' . $timed . '<br>';
strtolower()
和strtoupper()
与hello world
,HELLO WORLD
和Hello World
重复。 Here is the full gist.我已多次运行代码并继续获得大致相同的结果。这是以下一次测试。
strtolower hello world - 0.043829
strtoupper hello world - 0.04062
strtolower HELLO WORLD - 0.042691
strtoupper HELLO WORLD - 0.015475
strtolower Hello World - 0.033626
strtoupper Hello World - 0.017022
我相信php-src github中控制此问题的C代码适用于strtolower(),此处代表strtoupper()
要明确,这不会阻止我使用strtolower()
。我只是想了解这里发生了什么。
为什么strtolower()
比strtoupper()
慢?
答案 0 :(得分:4)
它主要取决于您当前使用的字符编码,但速度差异的主要原因是特殊字符的每个编码字符的大小。
例如,带有caron(ǰ)的小写j表示为单个编码字符(U + 01F0 LATIN SMALL LETTER J WITH CARON),但相应的大写字符(J̌)在Unicode中表示为序列两个编码字符(U + 004A LATIN CAPITAL LETTER J + U + 030C COMBINING CARON)。
在Unicode字符索引中筛选更多数据将不可避免地需要更长时间。
请注意,strtolower
使用您当前的区域设置,因此如果您的服务器使用的字符编码不支持strtolower
特殊字符(例如'Ê'),那么只会返回特殊字符。但是,设置了UTF-8上的字符映射,可以通过运行mb_strtolower来确认。
还有可能将属于uppercase
类别的字符数与您在lowercase
类别中找到的数量进行比较,但这又取决于您的角色编码
简而言之,strtolower
有一个更大的字符数据库,用于比较每个字符串字符与检查字符是否为uppercase
时的字符。
答案 1 :(得分:4)
代码的实现存在一些非常小的差异:
PHPAPI char *php_strtoupper(char *s, size_t len)
{
unsigned char *c, *e;
c = (unsigned char *)s;
e = (unsigned char *)c+len; <-- strtolower uses e = c+len;
while (c < e) {
*c = toupper(*c);
c++;
}
return s;
}
PHPAPI zend_string *php_string_toupper(zend_string *s)
{
unsigned char *c, *e;
c = (unsigned char *)ZSTR_VAL(s);
e = c + ZSTR_LEN(s);
while (c < e) {
if (islower(*c)) {
register unsigned char *r;
zend_string *res = zend_string_alloc(ZSTR_LEN(s), 0);
if (c != (unsigned char*)ZSTR_VAL(s)) {
memcpy(ZSTR_VAL(res), ZSTR_VAL(s), c - (unsigned char*)ZSTR_VAL(s));
}
r = c + (ZSTR_VAL(res) - ZSTR_VAL(s));
while (c < e) {
*r = toupper(*c);
r++;
c++;
}
*r = '\0';
return res;
}
c++;
}
return zend_string_copy(s);
}
PHP_FUNCTION(strtoupper)
{
zend_string *arg; <-- strtolower uses zend_string *str;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_STR(arg) <-- strtolower uses Z_PARAM_STR(str)
ZEND_PARSE_PARAMETERS_END();
RETURN_STR(php_string_toupper(arg)); <-- strtolower uses RETURN_STR(php_string_tolower(str));
}
和strtolower
PHPAPI char *php_strtolower(char *s, size_t len)
{
unsigned char *c, *e;
c = (unsigned char *)s;
e = c+len; <-- strtoupper uses e = (unsigned char *)c+len;
while (c < e) {
*c = tolower(*c);
c++;
}
return s;
}
PHPAPI zend_string *php_string_tolower(zend_string *s)
{
unsigned char *c, *e;
c = (unsigned char *)ZSTR_VAL(s);
e = c + ZSTR_LEN(s);
while (c < e) {
if (isupper(*c)) {
register unsigned char *r;
zend_string *res = zend_string_alloc(ZSTR_LEN(s), 0);
if (c != (unsigned char*)ZSTR_VAL(s)) {
memcpy(ZSTR_VAL(res), ZSTR_VAL(s), c - (unsigned char*)ZSTR_VAL(s));
}
r = c + (ZSTR_VAL(res) - ZSTR_VAL(s));
while (c < e) {
*r = tolower(*c);
r++;
c++;
}
*r = '\0';
return res;
}
c++;
}
return zend_string_copy(s);
}
PHP_FUNCTION(strtolower)
{
zend_string *str; <-- strtoupper uses zend_string *arg;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_STR(str) <-- strtoupper uses Z_PARAM_STR(arg)
ZEND_PARSE_PARAMETERS_END();
RETURN_STR(php_string_tolower(str)); <-- strtoupper uses RETURN_STR(php_string_tolower(arg));
}
这些微小的差异是否足以影响这几纳秒的性能,我不知道......不确定为什么差异就在那里