9

示例文本:

$text = 'Administration\Controller\UserController::Save';

任务 - 在 :: 之前提取所有内容

选项1:

list($module) = explode('::',$text);

选项 2:

$module = substr($text, 0, strpos($text, '::');

哪个选项更有效?

4

6 回答 6

15

我进行了测试,似乎第一个解决方案更快。这是测试它的代码:

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 秒内完成。

于 2013-09-16T11:44:05.170 回答
9

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在内存中操作输入字符串,返回子字符串。

于 2013-09-16T12:01:16.127 回答
7

在我的系统上:

~/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 版本可能会有不同的结果。您必须自己检查它,并确保在与您的生产相同的环境配置中。

于 2013-09-16T11:38:20.740 回答
1

已测试:极限爆炸(解决方案 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 使用率

于 2018-11-30T14:01:10.880 回答
0

time在 Linux 上使用命令。第一个在 处测量,0m0.024s第二个在 处测量0m0.011s

第二个似乎更快。我多次运行它,结果(一次酒吧)似乎是一样的。

编辑:正如建议的那样,另一个用户说要在 5000 的循环中运行它。这完成了相同的结果。

于 2013-09-16T11:31:53.050 回答
-2

高效的 ?如果你的意思是执行时间。然后在循环多次(1000)时间运行每个并检查执行时间。

于 2013-09-16T11:31:46.853 回答