루프 본문 내에서 array_push()를 사용하지 마세요.

Robert De Niro
풀어 주다: 2023-04-06 22:54:01
원래의
3650명이 탐색했습니다.

루프 본문 내에서 array_push()를 사용하지 마세요.

제목은 루프 본문에array_push()를 사용하지 마세요입니다. 사실 이것은 이 글의 결론 중 하나일 뿐입니다.
php를 공부해 보겠습니다 함께 언어의 배열에 요소 추가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的长度将根据入栈变量的数目增加。和如下效果相同:

로그인 후 복사

并对每个传入的值重复以上动作。

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에 배열 끝에 요소를 추가하는 두 가지 방법이 있다는 것을 알고 있습니다. stack
    • $a = []; array_push($a,'test');
  • $a[] = 'test';

    그러면 이 두 가지 방법의 차이점은 무엇인가요?

    성능을 먼저 비교해 보겠습니다

    ArrayPush

    ArrayPush클래스
    • pushEachOne()루프 본문 사용array_push()$a에 요소를 추가합니다.
    • pushEachTwo()루프 본문에$a[]를 사용합니다. $var$a
    rrreee

    쓰기 코드 테스트

    Loop에 요소를 추가합니다. 1백만 개의 요소 blockquote >rrreee

    결과

    결과는 자명합니다. $a[] =array_push()를 사용하는 것보다 거의 3배 빠릅니다.
    rrreee

    분석

    array_push()가 왜 느린가요? 너무 느린데, 사용할 수 있는 시나리오가 있나요?

    공식 매뉴얼

    array_push — 하나 이상의 셀을 배열의 끝으로 푸시합니다(push) array_push ( array &$array, 혼합 $value1[, 혼합 $...] ) : int array_push() 배열처리 이를 스택으로 만들고 전달된 변수를 배열끝에 푸시합니다. 배열의 길이는 스택에 푸시된 변수 수만큼 늘어납니다. rrreee와 동일한 효과이며 들어오는 값마다 반복합니다.
    참고: array_push()를 사용하여 배열에 단위를 추가하는 경우 $array[] =를 사용하는 것이 좋습니다. em> 왜냐하면 이렇게 하면 함수를 호출하는데 추가적인 부담이 없기 때문입니다.참고:array_push()는 첫 번째 인수가 배열이 아닌 경우 경고를 표시합니다. 이는 새 배열을 생성하는$var[]의 동작과 다릅니다.

    공식 소스 코드

    소스 코드에서 array_push()를 보세요
    rrreee $ a[ ] =는 지정된 변수 유형에 따라 일련의 Zend_API함수 add_next_index_*를 호출하여 구현됩니다. zend_hash_next_index_insertrrreee

    요약

    위의 분석을 해보면 array_push()는 정말 존재의미가 없는 것 같습니다. 사건?
    • 일반적으로array_push()의 성능이 너무 낮으므로$array[] =를 사용하여 교체해야 합니다
    • 한 번에 여러 단위를 추가하는 경우array_push()를 사용하세요. 더 많은 PHP 관련 기술 기사를 보려면 PHP Tutorial 열을 방문하여 알아보세요!

위 내용은 루프 본문 내에서 array_push()를 사용하지 마세요.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
php
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿
회사 소개 부인 성명 Sitemap
PHP 중국어 웹사이트:공공복지 온라인 PHP 교육,PHP 학습자의 빠른 성장을 도와주세요!