PHP list+explode VS substr+strpos - what is more efficient?

坚强是说给别人听的谎言 提交于 2020-01-01 09:04:08

问题


Sample text:

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

Task - extract everything before ::

Option 1:

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

Option 2:

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

Which option is more efficient?


回答1:


I ran a test and seems like the first solution is faster. Here is the code for testing it:

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

Test 1: Did solution1 in 0.19701099395752 seconds. Did solution2 in 0.38502216339111 seconds.

Test 2: Did solution1 in 0.1990110874176 seconds. Did solution2 in 0.37402105331421 seconds.

Test 3: Did solution1 in 0.19801092147827 seconds. Did solution2 in 0.37002205848694 seconds.




回答2:


substr+strpos will be faster and take less cpu time and use less memeroy.

Let's find out the answer from php soruce code.

explode first:

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 will call php_memnstr multiple times and add_next_index_stringl multiple times which will operate the result list.

Now 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);
}

It calls php_memnstr only one time, and substr operates the input string in memery, return the sub one.




回答3:


On my system:

~/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

I have results:

~/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%

Test code here: link. From time to time results slightly different, but list+explode is always faster more than 15%.

Different systems and PHP versions may have different results. You must check it by yourself and for sure in environment configuration identical to your production.




回答4:


Tested: explode with limit (solution3) Tested: preg_match

note: 10000 is not enough for me, so I run with 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";
}

And the results are:

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.

The solution3 is take longer than the solution1!

ran on cli, 100% cpu usage on 1 thread




回答5:


Using the time command on Linux. The first one measured in at 0m0.024s and the second at 0m0.011s.

The second one appears to be faster. I ran it multiple times and the result (bar one time) seemed to be the same.

EDIT: As suggested, the other user said to run it in a loop of 5000. That completed with the same results.




回答6:


efficient ? if you mean by execution time. then run each in a loop multiple (1000) time and check the execution time.



来源:https://stackoverflow.com/questions/18826797/php-listexplode-vs-substrstrpos-what-is-more-efficient

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!