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

后端 未结 6 1629
迷失自我
迷失自我 2021-01-04 22:24

Sample text:

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

Task - extract everything before ::

Option 1:

         


        
相关标签:
6条回答
  • 2021-01-04 22:32

    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.

    0 讨论(0)
  • 2021-01-04 22:33

    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.

    0 讨论(0)
  • 2021-01-04 22:34

    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.

    0 讨论(0)
  • 2021-01-04 22:48

    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.

    0 讨论(0)
  • 2021-01-04 22:48

    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

    0 讨论(0)
  • 2021-01-04 22:56

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

    0 讨论(0)
提交回复
热议问题