Maison  >  Article  >  développement back-end  >  N'utilisez pas array_push() dans le corps d'une boucle

N'utilisez pas array_push() dans le corps d'une boucle

步履不停
步履不停original
2019-07-01 17:43:573775parcourir

N'utilisez pas array_push() dans le corps d'une boucle

Le titre est de ne pas utiliser array_push() dans un corps de boucle. En fait, ce n'est qu'une des conclusions de cet article
Étudions ensemble php en annexe. aux tableaux dans le langage Element

Ajouter des éléments au tableau

Nous savons que php il existe deux façons d'ajouter des éléments à la fin de la pile du tableau

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

Alors quelle est la différence entre ces deux méthodes ?

Comparons d'abord les performances

ArrayPush

Une ArrayPush classe

  • pushEachOne() utilisée dans le corps de la bouclearray_push() pour ajouter des éléments pour $a
  • pushEachTwo() Utilisez $a[] = $var dans le corps de la boucle pour ajouter des éléments à $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;
    }

}

pour écrire des tests de code

Boucle pour ajouter 1 million d'éléments

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;

Le résultat

Le résultat va de soi, $a[] = est presque plus rapide que en utilisant array_push() Trois fois

count pushEachOne result | 1000000
count pushEachTwo result | 1000000

pushEachOne | 1.757071018219
pushEachTwo | 0.67165303230286

Analyse

Pourquoi array_push() est-il lent ? C'est si lent, existe-t-il des scénarios dans lesquels nous pouvons l'utiliser ?

Manuel officiel

array_push — Pousser une ou plusieurs cellules jusqu'à la fin du tableau (push)

array_push ( array &$array , mixte $value1 [, Mixed $... ] ) : int

array_push() traite array comme une pile et pousse les variables transmises à la fin de array . La longueur de array sera augmentée en fonction du nombre de variables placées sur la pile. A le même effet que :

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

et se répète pour chaque valeur passée.

Remarque : Si vous utilisez array_push() pour ajouter une unité au tableau, il est préférable d'utiliser $array[] = Parce qu'il n'y a pas de charge supplémentaire pour appeler des fonctions.

Remarque : array_push() émettra un avertissement si le premier argument n'est pas un tableau. Ceci est différent du comportement de $var[] qui crée un nouveau tableau.

Code source officiel

Regardez le code source 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[] = est implémenté sur la base de. affectation Le type de variable appelle une série de Zend_API fonctions add_next_index_*, qui appellent directement 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;
}
/* }}} */

après avoir défini une valeur zval du type correspondant

Après l'analyse ci-dessus. , semble-t-il array_push() Cela n'a aucun sens d'exister. Est-ce vraiment le cas ?

  • Généralement, les performances de array_push() sont trop mauvaises, nous devrions donc utiliser $array[] = pour le remplacer
  • Si vous ajoutez plusieurs unités à la fois, utilisez array_push()

Pour plus d'articles techniques liés à PHP, veuillez visiter la colonne Tutoriel PHP pour apprendre !

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn