首頁  >  文章  >  後端開發  >  不要在循環體中使用array_push()

不要在循環體中使用array_push()

步履不停
步履不停原創
2019-07-01 17:43:573775瀏覽

不要在循環體中使用array_push()

標題是不要在循環體中使用array_push(),其實這只是這篇文章的結論之一
下面我們一起研究一下php 語言中陣列的追加元素

向陣列追加元素

#我們知道php 在陣列棧尾追加元素的方式有兩種

  • $a = []; array_push($a,'test');
  • $a[] = 'test';

那麼這兩種方式有什麼差別呢?

我們先來比較一下效能

ArrayPush

一個ArrayPush 類別

  • pushEachOne () 循環體中使用array_push() 來為$a 追加元素
  • ##pushEachTwo() 循環體中使用$a[] = $var 來為$a 追加元素
#
/**
 * Class ArrayPush
 */
class ArrayPush
{

    /**
     * @param int $times
     * @return array
     */
    public static function pushEachOne(int $times): array
    {
        $a = [];
        $b = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
        for ($i = 0; $i < $times; $i++) {
            array_push($a, $b[$i % 10]);
        }
        return $a;
    }

    /**
     * @param int $times
     * @return array
     */
    public static function pushEachTwo(int $times): array
    {
        $a = [];
        $b = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
        for ($i = 0; $i < $times; $i++) {
            $a[] = $b[$i % 10];
        }
        return $a;
    }

}
編寫程式碼測試

循環追加100萬個元素

ini_set(&#39;memory_limit&#39;, &#39;4000M&#39;);
$timeOne = microtime(true);
$a       = ArrayPush::pushEachOne(1000000);
echo &#39;count pushEachOne result | &#39; . count($a) . PHP_EOL;
$timeTwo = microtime(true);
$b       = ArrayPush::pushEachTwo(1000000);
echo &#39;count pushEachTwo result | &#39; . count($b) . PHP_EOL;
$timeThree = microtime(true);
echo PHP_EOL;
echo &#39;pushEachOne | &#39; . ($timeTwo - $timeOne) . PHP_EOL;
echo &#39;pushEachTwo | &#39; . ($timeThree - $timeTwo) . PHP_EOL;
echo PHP_EOL;
結果

結果不言而喻,

$a[] = 比使用array_push() 快了接近三倍

count pushEachOne result | 1000000
count pushEachTwo result | 1000000

pushEachOne | 1.757071018219
pushEachTwo | 0.67165303230286
分析

array_push()為什麼慢?這麼慢,我們還有使用它的場景嗎?

官方手冊

array_push — 將一個或多個單元壓入陣列的末端(入堆疊)

array_push ( array

& $array , mixed $value1 [, mixed $... ] ) : int

##array_push()

將會array 當成堆疊,並將傳入的變數壓入array 的結尾。 array 的長度將根據入棧變數的數目增加。和如下效果相同:<pre class="brush:php;toolbar:false">&lt;?php$array[] = $var;?&gt;</pre>並對每個傳入的值重複以上動作。 <p></p> <blockquote>Note<p>: 如果用<strong>array_push()</strong> 來為陣列增加一個單元,不如用<strong>\$array[] =</strong> ,因為這樣沒有呼叫函數的額外負擔。 <em></em></p>Note<p>: 如果第一個參數不是數組,<strong>array_push()</strong> 將發出警告。這和 <strong>\$var[]</strong> 的行為不同,後者會新建一個陣列。 <em></em></p> </blockquote>官方原始碼</blockquote> <h2></h2>看一下原始碼中的<blockquote>array_push()<p><code>

/* {{{ proto int array_push(array stack, mixed var [, mixed ...])
   Pushes elements onto the end of the array */
PHP_FUNCTION(array_push)
{
    zval   *args,       /* Function arguments array */
           *stack,      /* Input array */
            new_var;    /* Variable to be pushed */
    int i,              /* Loop counter */
        argc;           /* Number of function arguments */

    //这一段是函数的参数解析
    ZEND_PARSE_PARAMETERS_START(2, -1)
        Z_PARAM_ARRAY_EX(stack, 0, 1)
        Z_PARAM_VARIADIC('+', args, argc)
    ZEND_PARSE_PARAMETERS_END();

    /* For each subsequent argument, make it a reference, increase refcount, and add it to the end of the array */
    for (i = 0; i < argc; i++) {
        //拷贝一个
        ZVAL_COPY(&new_var, &args[i]);

        //插入新数值,自动
        if (zend_hash_next_index_insert(Z_ARRVAL_P(stack), &new_var) == NULL) {
            if (Z_REFCOUNTED(new_var)) Z_DELREF(new_var);
            php_error_docref(NULL, E_WARNING, "Cannot add element to the array as the next element is already occupied");
            RETURN_FALSE;
        }
    }

    /* Clean up and return the number of values in the stack */
    RETVAL_LONG(zend_hash_num_elements(Z_ARRVAL_P(stack)));
}
/* }}} */
# $a[] =

的實作是根據賦值的變數類型呼叫了一系列Zend_API 函數add_next_index_* ,它們在設定一個對應類型的zval 值以後直接呼叫了zend_hash_next_index_insert<pre class="brush:php;toolbar:false">ZEND_API int add_next_index_long(zval *arg, zend_long n) /* {{{ */ {     zval tmp;     ZVAL_LONG(&amp;tmp, n);     return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &amp;tmp) ? SUCCESS : FAILURE; } /* }}} */ ZEND_API int add_next_index_null(zval *arg) /* {{{ */ {     zval tmp;     ZVAL_NULL(&amp;tmp);     return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &amp;tmp) ? SUCCESS : FAILURE; } /* }}} */ ZEND_API int add_next_index_bool(zval *arg, int b) /* {{{ */ {     zval tmp;     ZVAL_BOOL(&amp;tmp, b);     return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &amp;tmp) ? SUCCESS : FAILURE; } /* }}} */ ZEND_API int add_next_index_resource(zval *arg, zend_resource *r) /* {{{ */ {     zval tmp;     ZVAL_RES(&amp;tmp, r);     return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &amp;tmp) ? SUCCESS : FAILURE; } /* }}} */ ZEND_API int add_next_index_double(zval *arg, double d) /* {{{ */ {     zval tmp;     ZVAL_DOUBLE(&amp;tmp, d);     return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &amp;tmp) ? SUCCESS : FAILURE; } /* }}} */ ZEND_API int add_next_index_str(zval *arg, zend_string *str) /* {{{ */ {     zval tmp;     ZVAL_STR(&amp;tmp, str);     return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &amp;tmp) ? SUCCESS : FAILURE; } /* }}} */ ZEND_API int add_next_index_string(zval *arg, const char *str) /* {{{ */ {     zval tmp;     ZVAL_STRING(&amp;tmp, str);     return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &amp;tmp) ? SUCCESS : FAILURE; } /* }}} */ ZEND_API int add_next_index_stringl(zval *arg, const char *str, size_t length) /* {{{ */ {     zval tmp;     ZVAL_STRINGL(&amp;tmp, str, length);     return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &amp;tmp) ? SUCCESS : FAILURE; } /* }}} */ ZEND_API int add_next_index_zval(zval *arg, zval *value) /* {{{ */ {     return zend_hash_next_index_insert(Z_ARRVAL_P(arg), value) ? SUCCESS : FAILURE; } /* }}} */</pre>總結

經過上面的分析,彷彿

array_push()

沒有任何存在的意義,真的是這樣嗎?

一般情況下,
    array_push()
  • 效能太差,所以我們應該使用$array[] = 來替換掉它
  • #如果一次追加多個單元,使用
  • array_push()

  • #更多PHP相關技術文章,請造訪
PHP教學

欄位進行學習!

以上是不要在循環體中使用array_push()的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn