内容简介:标题是不要在循环体中使用那么这两种方式有什么区别呢?我们先来比较一下性能
标题是不要在循环体中使用 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()
参考
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- [源码分析系列] 不要在循环体中使用 array_merge()
- 【源码阅读】AndPermission源码阅读
- ReactNative源码解析-初识源码
- 【源码阅读】Gson源码阅读
- Spring源码系列:BeanDefinition源码解析
- istio 源码 – Citadel 源码分析 (原创)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
More Eric Meyer on CSS (Voices That Matter)
Eric A. Meyer / New Riders Press / 2004-04-08 / USD 45.00
Ready to commit to using more CSS on your sites? If you are a hands-on learner who has been toying with CSS and want to experiment with real-world projects that will enable you to see how CSS......一起来看看 《More Eric Meyer on CSS (Voices That Matter)》 这本书的介绍吧!