Home  >  Article  >  Backend Development  >  Don't use array_push() inside a loop body

Don't use array_push() inside a loop body

步履不停
步履不停Original
2019-07-01 17:43:573769browse

Don't use array_push() inside a loop body

The title is don’t use array_push() in the loop body. In fact, this is just one of the conclusions of this article
Let’s study it togetherphp Appending elements to arrays in the language

Appending elements to arrays

We know thatphp There are two ways to append elements to the end of the array stack

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

So what is the difference between these two methods?

Let’s compare the performance first

ArrayPush

OneArrayPush Class

  • pushEachOne () Use array_push() in the loop body to append elements to $a
  • pushEachTwo() Use ## in the loop body #$a[] = $var to append elements to $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;
    }

}
Write code test

Loop append 100 Ten thousand elements

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;
The result

The result is self-evident,

$a[] = is better than using array_push() Nearly three times faster

count pushEachOne result | 1000000
count pushEachTwo result | 1000000

pushEachOne | 1.757071018219
pushEachTwo | 0.67165303230286
Analysis

Why is array_push() slow? It's so slow, are there any scenarios where we can use it?

Official Manual

array_push — Push one or more elements to the end of the array (push)

array_push ( array

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

array_push() will array treats it as a stack and pushes the passed variables into the end of array. The length of array will increase according to the number of variables pushed onto the stack. Has the same effect as:

<?php$array[] = $var;?>
and repeats the above action for each incoming value.

Note: If you use array_push() to add a unit to the array, it is better to use \$array[] = , because there is no additional burden of calling functions.

Note: array_push() will issue a warning if the first argument is not an array. This is different from the behavior of \$var[], which creates a new array.

Official source code

Look at

array_push()

/* {{{ 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)));
}
/* }}} */

in the source code The implementation of $a[] = is to call a series of Zend_API functions add_next_index_* according to the assigned variable type. They are called directly after setting a zval value of the corresponding type. zend_hash_next_index_insert

ZEND_API int add_next_index_long(zval *arg, zend_long n) /* {{{ */
{
    zval tmp;

    ZVAL_LONG(&tmp, n);
    return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp) ? SUCCESS : FAILURE;
}
/* }}} */

ZEND_API int add_next_index_null(zval *arg) /* {{{ */
{
    zval tmp;

    ZVAL_NULL(&tmp);
    return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp) ? SUCCESS : FAILURE;
}
/* }}} */

ZEND_API int add_next_index_bool(zval *arg, int b) /* {{{ */
{
    zval tmp;

    ZVAL_BOOL(&tmp, b);
    return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp) ? SUCCESS : FAILURE;
}
/* }}} */

ZEND_API int add_next_index_resource(zval *arg, zend_resource *r) /* {{{ */
{
    zval tmp;

    ZVAL_RES(&tmp, r);
    return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp) ? SUCCESS : FAILURE;
}
/* }}} */

ZEND_API int add_next_index_double(zval *arg, double d) /* {{{ */
{
    zval tmp;

    ZVAL_DOUBLE(&tmp, d);
    return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp) ? SUCCESS : FAILURE;
}
/* }}} */

ZEND_API int add_next_index_str(zval *arg, zend_string *str) /* {{{ */
{
    zval tmp;

    ZVAL_STR(&tmp, str);
    return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp) ? SUCCESS : FAILURE;
}
/* }}} */

ZEND_API int add_next_index_string(zval *arg, const char *str) /* {{{ */
{
    zval tmp;

    ZVAL_STRING(&tmp, str);
    return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp) ? SUCCESS : FAILURE;
}
/* }}} */

ZEND_API int add_next_index_stringl(zval *arg, const char *str, size_t length) /* {{{ */
{
    zval tmp;

    ZVAL_STRINGL(&tmp, str, length);
    return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &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;
}
/* }}} */
Summary

After the above analysis, it seems that

array_push() has no meaning of existence. Is this really the case?

    Generally,
  • array_push() has poor performance, so we should use $array[] = to replace it
  • If you append multiple units at one time, use

    array_push()

For more PHP related technical articles, please visit

PHP Tutorial Column for learning!

The above is the detailed content of Don't use array_push() inside a loop body. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn