缓慢的原因
查看 PHP 5.5.6 源文件后,我们发现延迟主要出现在 mbfilter.c 中,正如hakre所猜测的那样 - 每次调用mb_strpos
(或者我猜大部分的mb_*
函数),都需要验证和转换both haystack 和 needle:
除非haystack是默认格式,否则将其编码为默认格式:
if (haystack->no_encoding != mbfl_no_encoding_utf8) {
mbfl_string_init(&_haystack_u8);
haystack_u8 = mbfl_convert_encoding(haystack, &_haystack_u8, mbfl_no_encoding_utf8);
if (haystack_u8 == NULL) {
result = -4;
goto out;
}
} else {
haystack_u8 = haystack;
}
除非针是默认格式,否则将其编码为默认格式:
if (needle->no_encoding != mbfl_no_encoding_utf8) {
mbfl_string_init(&_needle_u8);
needle_u8 = mbfl_convert_encoding(needle, &_needle_u8, mbfl_no_encoding_utf8);
if (needle_u8 == NULL) {
result = -4;
goto out;
}
} else {
needle_u8 = needle;
}
根据使用 valgrind
的快速检查,编码转换占了 mb_strpos
运行时间的很大一部分,约为总运行时间的84%,或五分之六:
218,552,085 ext/mbstring/libmbfl/mbfl/mbfilter.c:mbfl_strpos [/usr/src/php-5.5.6/sapi/cli/php]
183,812,085 ext/mbstring/libmbfl/mbfl/mbfilter.c:mbfl_convert_encoding [/usr/src/php-5.5.6/sapi/cli/php]
这似乎与OP的mb_strpos
与strpos
的时间相一致。
没有考虑编码,mb_strpos
字符串与strpos
字符串是完全相同的,仅在字符串略长时会有所不同。如果您遇到非常麻烦的字符串,那么最多会长四倍,但即使如此,您也只会因为编码时间而延迟四倍,而不是二十倍。额外的5-6倍减速来源于编码时间。
加速 mb_strpos
...
那么你该怎么办呢?您可以通过确保在mbfl*
进行转换和比较的“基本”格式中内部已经有了字符串来跳过这两个步骤,该格式为mbfl_no_encoding_utf8
(UTF-8):
- 将数据保留在UTF-8格式中。
- 尽快将用户输入转换为UTF-8格式。
- 如有必要,则将其转换回客户端编码。
然后您的伪代码:
$haystack = "...";
$needle = "...";
$res = mb_strpos($haystack, $needle, 0, $Encoding);
变成:
$haystack = "...";
$needle = "...";
mb_internal_encoding('UTF-8') or die("Cannot set encoding");
$haystack = mb_convert_encoding($haystack, 'UTF-8' [, $SourceEncoding]);
$needle = mb_convert_encoding($needle, 'UTF-8', [, $SourceEncoding]);
$res = mb_strpos($haystack, $needle, 0);
...当它值得
当整个UTF-8基础的“设置时间”和维护明显小于在每个mb_*
函数中隐式地进行转换的“运行时间”时,这当然是方便的。
/u
标志,因此很可能只进行了二进制比较。 - mariopreg_match
(没有u
修饰符)可以工作,那么普通的strpos
一定 也可以工作(而且显然会更快)。请澄清一下。 - Jonmb_strpos
唯一能做到的一件事是告诉你子字符串的 字符 偏移量,而不管输入编码是什么。 - Jon