示例文本:
$text = 'Administration\Controller\UserController::Save';
任务 - 在 :: 之前提取所有内容
选项1:
list($module) = explode('::',$text);
选项 2:
$module = substr($text, 0, strpos($text, '::');
哪个选项更有效?
我进行了测试,似乎第一个解决方案更快。这是测试它的代码:
function microtime_float()
{
list($usec, $sec) = explode(" ", microtime());
return ((float)$usec + (float)$sec);
}
function solution1($text)
{
for($i = 0; $i < 10000; $i++)
list($module) = explode('::',$text);
}
function solution2($text)
{
for($i = 0; $i < 10000; $i++)
$module = substr($text, 0, strpos($text, '::'));
}
$text = 'Administration\Controller\UserController::Save';
$time_start = microtime_float();
solution1($text);
$time_end = microtime_float();
$time = $time_end - $time_start;
echo "Did solution1 in $time seconds.\n";
$time_start = microtime_float();
solution2($text);
$time_end = microtime_float();
$time = $time_end - $time_start;
echo "Did solution2 in $time seconds.\n";
测试 1:solution1 在 0.19701099395752 秒内完成。解决方案 2 在 0.38502216339111 秒内完成。
测试 2:solution1 在 0.1990110874176 秒内完成。解决方案 2 在 0.37402105331421 秒内完成。
测试 3:solution1 在 0.19801092147827 秒内完成。解决方案 2 在 0.37002205848694 秒内完成。
substr+strpos
会更快,占用更少的 CPU 时间并使用更少的内存。
让我们从 php 源代码中找出答案。
explode
第一的:
PHP_FUNCTION(explode)
{
// other codes
array_init(return_value);
if (str_len == 0) {
if (limit >= 0) {
add_next_index_stringl(return_value, "", sizeof("") - 1, 1);
}
return;
}
// other code
if (limit > 1) {
php_explode(&zdelim, &zstr, return_value, limit);
} else if (limit < 0) {
php_explode_negative_limit(&zdelim, &zstr, return_value, limit);
} else {
add_index_stringl(return_value, 0, str, str_len, 1);
}
}
PHPAPI void php_explode(zval *delim, zval *str, zval *return_value, long limit)
{
char *p1, *p2, *endp;
endp = Z_STRVAL_P(str) + Z_STRLEN_P(str);
p1 = Z_STRVAL_P(str);
p2 = php_memnstr(Z_STRVAL_P(str), Z_STRVAL_P(delim), Z_STRLEN_P(delim), endp);
if (p2 == NULL) {
add_next_index_stringl(return_value, p1, Z_STRLEN_P(str), 1);
} else {
do {
add_next_index_stringl(return_value, p1, p2 - p1, 1);
p1 = p2 + Z_STRLEN_P(delim);
} while ((p2 = php_memnstr(p1, Z_STRVAL_P(delim), Z_STRLEN_P(delim), endp)) != NULL &&
--limit > 1);
if (p1 <= endp)
add_next_index_stringl(return_value, p1, endp-p1, 1);
}
}
explode
将调用php_memnstr
多次和add_next_index_stringl
多次将运行the result list
。
现在strpos
:
PHP_FUNCTION(strpos)
{
zval *needle;
char *haystack;
char *found = NULL;
char needle_char[2];
long offset = 0;
int haystack_len;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|l", &haystack, &haystack_len, &needle, &offset) == FAILURE) {
return;
}
if (offset < 0 || offset > haystack_len) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset not contained in string");
RETURN_FALSE;
}
if (Z_TYPE_P(needle) == IS_STRING) {
if (!Z_STRLEN_P(needle)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty needle");
RETURN_FALSE;
}
found = php_memnstr(haystack + offset,
Z_STRVAL_P(needle),
Z_STRLEN_P(needle),
haystack + haystack_len);
} else {
if (php_needle_char(needle, needle_char TSRMLS_CC) != SUCCESS) {
RETURN_FALSE;
}
needle_char[1] = 0;
found = php_memnstr(haystack + offset,
needle_char,
1,
haystack + haystack_len);
}
if (found) {
RETURN_LONG(found - haystack);
} else {
RETURN_FALSE;
}
}
PHP_FUNCTION(substr)
{
// other code about postion
RETURN_STRINGL(str + f, l, 1);
}
它只调用php_memnstr
一次,并substr
在内存中操作输入字符串,返回子字符串。
在我的系统上:
~/pb$ uname -a && php -v
Linux hostname 3.2.0-4-amd64 #1 SMP Debian 3.2.46-1+deb7u1 x86_64 GNU/Linux
PHP 5.4.19-1~dotdeb.1 (cli) (built: Aug 27 2013 00:42:43)
Copyright (c) 1997-2013 The PHP Group
Zend Engine v2.4.0, Copyright (c) 1998-2013 Zend Technologies
with XCache v3.0.3, Copyright (c) 2005-2013, by mOo
with Xdebug v2.2.3, Copyright (c) 2002-2013, by Derick Rethans
with XCache Cacher v3.0.3, Copyright (c) 2005-2013, by mOo
我有结果:
~/pb$ ./test ListVsSubstr
[============================================================>] 1000 u | 8134 u/s | Est: 0.0 s | Mem: 335.74 KB | Max: 357.96 KB
[============================================================>] 1000 u | 7808 u/s | Est: 0.0 s | Mem: 336.14 KB | Max: 357.96 KB
Test name Repeats Result Performance
list+explode 1000 0.044890 sec +0.00%
substr+strpos 1000 0.052825 sec -17.68%
测试代码在这里:链接。有时结果略有不同,但list+explode
总是快于 15% 以上。
不同的系统和 PHP 版本可能会有不同的结果。您必须自己检查它,并确保在与您的生产相同的环境配置中。
已测试:极限爆炸(解决方案 3)已测试:preg_match
注意:10000 对我来说还不够,所以我用 10 000 000 x 3 运行
<?php
function microtime_float()
{
list($usec, $sec) = explode(" ", microtime());
return ((float)$usec + (float)$sec);
}
function solution1($text)
{
for($i = 0; $i < 10000000; $i++)
list($module) = explode('::',$text);
}
function solution2($text)
{
for($i = 0; $i < 10000000; $i++)
$module = substr($text, 0, strpos($text, '::'));
}
function solution3($text)
{
for($i = 0; $i < 10000000; $i++)
list($module) = explode('::',$text, 2);
}
function solution4($text)
{
for($i = 0; $i < 10000000; $i++)
preg_match('/^(.*)::/', $text, $m) && $module = $m[1];
}
$text = 'Administration\Controller\UserController::Save';
for ($i=0; $i < 3; $i++) {
$time_start = microtime_float();
solution1($text);
$time_end = microtime_float();
$time = $time_end - $time_start;
echo "Did solution1 in $time seconds.\n";
$time_start = microtime_float();
solution2($text);
$time_end = microtime_float();
$time = $time_end - $time_start;
echo "Did solution2 in $time seconds.\n";
$time_start = microtime_float();
solution3($text);
$time_end = microtime_float();
$time = $time_end - $time_start;
echo "Did solution3 in $time seconds.\n";
}
结果是:
Did solution1 in 6.4486601352692 seconds.
Did solution2 in 9.4331159591675 seconds.
Did solution3 in 6.6791591644287 seconds.
Did solution4 in 9.3652379512787 seconds.
Did solution1 in 7.1072399616241 seconds.
Did solution2 in 10.755952835083 seconds.
Did solution3 in 7.5958750247955 seconds.
Did solution4 in 9.4377269744873 seconds.
Did solution1 in 7.4207429885864 seconds.
Did solution2 in 10.894104003906 seconds.
Did solution3 in 7.701789855957 seconds.
Did solution4 in 9.5081558227539 seconds.
解决方案3比解决方案1花费更长的时间!
在 cli 上运行,1 个线程上 100% 的 cpu 使用率
time
在 Linux 上使用命令。第一个在 处测量,0m0.024s
第二个在 处测量0m0.011s
。
第二个似乎更快。我多次运行它,结果(一次酒吧)似乎是一样的。
编辑:正如建议的那样,另一个用户说要在 5000 的循环中运行它。这完成了相同的结果。
高效的 ?如果你的意思是执行时间。然后在循环多次(1000)时间运行每个并检查执行时间。