不要在循环体中使用array_push()-php教程

资源魔 65 0

题目是没有要正在轮回体中应用 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('memory_limit', '4000M');
$timeOne = microtime(true);
$a       = ArrayPush::pushEachOne(1000000);
echo 'count pushEachOne result | ' . count($a) . PHP_EOL;
$timeTwo = microtime(true);
$b       = ArrayPush::pushEachTwo(1000000);
echo 'count pushEachTwo result | ' . count($b) . PHP_EOL;
$timeThree = microtime(true);
echo PHP_EOL;
echo 'pushEachOne | ' . ($timeTwo - $timeOne) . PHP_EOL;
echo 'pushEachTwo | ' . ($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 的长度将依据入栈变量的数量添加。以及以下成果相反:

<?php$array[] = $var;?>

并对每一个传入的值反复以上举措。

Note: 假如用 array_push() 来给数组添加一个单位,还没有如用 \$array[] = ,由于这样不挪用函数的额定累赘。

Note: 假如第一个参数没有是数组,array_push() 将收回一条正告。这以及 \$var[] 的行为没有同,后者会新建一个数组。

民间源码

看一下源码中的 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)));
}
/* }}} */

$a[] = 的完成是依据赋值的变量类型挪用了一系列 Zend_API 函数 add_next_index_* ,它们正在设置一个对应类型的 zval 值当前间接挪用了 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;
}
/* }}} */

总结

通过下面的剖析,似乎 array_push() 不任何存正在的意思,真的是这样吗?

  • 普通状况下,array_push() 功能太差,以是咱们该当应用 $array[] = 来交换掉它
  • 假如一次追加多个单位,应用 array_push()

更多PHP相干技巧文章,请拜访PHP教程栏目进行学习!

以上就是没有要正在轮回体中应用array_push()的具体内容,更多请存眷资源魔其它相干文章!

标签: php php开发教程 php开发资料 php开发自学

抱歉,评论功能暂时关闭!