PHP list + explode VS substr+strpos-что более эффективно?

текст:

$text = 'AdministrationControllerUserController::Save';

задача - извлечь все до ::

Вариант 1:

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

Вариант 2:

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

какой вариант более эффективен?

5 ответов


Я провел тест и кажется, что первое решение быстрее. Вот код для его тестирования:

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";

substr+strpos будет быстрее и займет меньше времени процессора и использовать меньше memeroy.

Давайте узнаем ответ из кода PHP soruce.

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 управляет входной строкой в memery, возвращает sub one.


на моей системе:

~/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 могут иметь разные результаты. Вы должны проверить его самостоятельно и наверняка в конфигурации среды, идентичной вашей продукции.


С помощью time команда в Linux. Первый измеряется в0m0.024s и второй 0m0.011s.

второй, кажется, быстрее. Я запускал его несколько раз, и результат (бар один раз) казался одинаковым.

EDIT: как было предложено, другой пользователь сказал, чтобы запустить его в цикле 5000. Это завершилось с теми же результатами.


эффективно ? если вы имеете в виду время исполнения. затем запустите каждый в цикле несколько (1000) раз и проверьте время выполнения.