web-dev-qa-db-fra.com

PHP 7 changements pour foreach: Puis-je quand même supprimer les éléments dans le tableau sur lequel j'itère?

Le PHP 7 Backward-Incompatible Changes Document dit ce qui suit à propos de foreach:

Lorsqu'il est utilisé dans le mode par valeur par défaut, foreach fonctionnera désormais sur une copie du tableau en cours d'itération plutôt que sur le tableau lui-même. Cela signifie que les modifications apportées au tableau lors de l'itération n'affecteront pas les valeurs qui sont itérées.

J'essaie de comprendre ce que cela signifie, et ma principale question est de savoir si ce code fonctionnera de la même manière dans PHP 7 que dans PHP 5.6?

foreach($array as $elementKey => $element) {
    if ($element == 'x') {
        unset($array[$elementKey]);
    }
}

Mes deux questions sont:

  1. Ce code fonctionnera-t-il toujours?

  2. Si oui, pouvez-vous expliquer (peut-être par exemple) ce que signifie ce nouveau changement dans PHP 7?

Modifier

J'ai relu la déclaration doc. Je pense que cela signifie que, si vous modifiez les valeurs des éléments plus bas dans le tableau, ces modifications ne seront pas là lorsque vous arriverez à ces éléments dans l'itération. Exemple:

$array = ['x', 'y', 'z'];

$new = [];

foreach($array as $element) {
    if ($element == 'x') {
        $array[2] = 'a';
    }

    $new[] = $element;
}

print_r($new);

Cependant, quand je exécutez cet exemple cela ne semble pas montrer de différence dans PHP versions (même si je n'ai jamais utilisé cet outil auparavant, je ne sais donc pas comment il fonctionne).

Je me rends compte que si je le fais par référence, j'obtiendrai un a dans new. Sinon, je ne le ferai pas. Mais cela semble être le cas dans les deux versions.

Ce que j'ai vraiment besoin de savoir c'est quelle est l'incompatibilité (par exemple)?

Édition 2

Le lien de réponse suggéré par @NikiC fournit le reste de l'histoire que je cherchais:

Dans la plupart des cas, ce changement est transparent et n'a d'autre effet que de meilleures performances. Cependant, il y a une occasion où il en résulte un comportement différent, à savoir le cas où le tableau était une référence au préalable:

$array = [1, 2, 3, 4, 5];
$ref = &$array;
foreach ($array as $val) {
    var_dump($val);
    $array[2] = 0;
}
/* Old output: 1, 2, 0, 4, 5 */
/* New output: 1, 2, 3, 4, 5 */

Auparavant, l'itération par valeur des tableaux de référence était des cas spéciaux. Dans ce cas, aucune duplication ne s'est produite, donc toutes les modifications du tableau pendant l'itération seraient reflétées par la boucle. Dans PHP 7, ce cas particulier a disparu: une itération par valeur d'un tableau continuera toujours à travailler sur les éléments d'origine, sans tenir compte des modifications pendant la boucle.

Cette réponse explique le rare "cas spécial" où les choses fonctionnent différemment entre les versions en ce qui concerne foreach fonctionnant sur une copie du tableau.

26
userlite

Tout cela signifie que vous devez maintenant dire explicitement que vous voulez référencer le tableau que vous itérez maintenant.

Dans votre exemple de code, cependant, vous faites quand même référence au tableau racine afin qu'il fonctionne, que vous passiez ou non par référence.

<?php
$array = ['x', 'y', 'z'];

foreach($array as $elementKey => $element) {
    if ($element=='x') {
        unset($array[$elementKey]);
    }
}

var_dump($array); // lists 'y' and 'z'

Un meilleur exemple. Dans ce cas, nous modifions la valeur à l'intérieur du foreach sans référence. En tant que tel, les modifications locales seront perdues:

<?php
$array = ['x', 'y', 'z'];

foreach($array as $element) {
    if ($element=='x') {
        $element = 'a';
    }
}

var_dump($array); // 'x', 'y', 'z'

Vs par référence, où nous déclarons le $element pour être une référence à l'élément de tableau:

<?php
$array = ['x', 'y', 'z'];

foreach($array as &$element) {
    if ($element=='x') {
        $element = 'a';
    }
}

var_dump($array); // 'a', 'y', 'z'

Voici une démo de ce code en cours d'exécution sur différentes versions de PHP.

23
Machavity