Débat : while() contre foreach() ?

Comment faites-vous vos boucles (de préférence) en PHP5 ?

Vous pouvez sélectionner 1 option
21
26%
1
1%
14
17%
45
56%
 
Nombre total de votes : 81
 
ViPHP
ViPHP | 2287 Messages

22 juin 2008, 15:45

Bonjour à tous,

Un jour, un collègue développeur m'a fermement soutenu qu'il était préférable d'utiliser systématiquement while() plutôt que for() ou foreach() pour boucler en php5.

Je ne me souviens que vaguement de ses arguments à cela, je me rappelle qu'il parlait de performance et de meilleur contrôle des éléments bouclés.

Je suis pour ma part partisan du foreach() qui apporte de la lisibilité au code, même si on doit le payer un peu en performances derrière. Sinon, quand je dois boucler sur un nombre d'éléments fixe, j'utilise for(), et pour une boucle non-bornée (potentiellement infinie) bien sûr j'utilise while(), voire do{...} while().

Et vous, qu'en pensez-vous ?
if(!@work()){ Nespresso(); } else { what(); }
______________________________

Mammouth du PHP | 1511 Messages

22 juin 2008, 15:52

Le problème dira t'on est le type de données traitées.
Dans une boucle en général on va traiter un tableau ou un contenu retourné sous forme de lignes, c'est l'exemple que je prendrais ici.
Le premier exemple qui me vient a l'idée est une banale requête SQL de type SELECT.
Avec l'extension mysql, on se retrouve avec un traitement sur une boucle while a cause de mysql_fetch_array qui traite la ressource en déplaceant un pointeur interne, sans manière de revenir en arrière.
Ensuite, nous avons pour la même requete avec PDO_MySql un tableau retourné que l'on peut traiter avec une boucle for ou foreach.

C'est sur que while est adapté au traitement de tableaux ou ressources dont on ne connait pas la taille, boucle dont on peut heureusement sortir a l'aide de l'ami "break;".

Je pense qu'après ca reste une histoire d'habitude.

Si quelqu'un avait un bench sous la main :)

Avatar du membre
Modérateur PHPfrance
Modérateur PHPfrance | 10684 Messages

22 juin 2008, 16:04

Le traitement derrière étant vraissemblablement le même, à savoir l'itération, je pense qu'en dehors d'une question de syntaxe, la performance doit pas spécialement être affecté... (et puis si le for était significativement moins performant que le while, ca fait bien longtemps qu'il aurait été signalé voire abandonné :))

Personnellement je fonctionne au contexte et surtout à l'habitude maintenant :
- J'utilise un while pour récupérer les données après un mysql_fetch
- Un for quand j'ai un nombre d'élément limité et invariable
- Un foreach quand je manipule un tableau associatif

Je n'utilise quasiment jamais le do/while sauf cas exceptionnel où je suis certain d'avoir besoin d'une itération au minimum (je ne supporte d'ailleurs pas de voir des codes avec un if() qui récupère le résultat d'une requête, suivi d'un do/while sur la même condition, alors que le while évite cette redondance).

Je n'utilise pas non plus les fonctions each() et list() (sauf cas exceptionnel), mais le foreach me dépanne généralement :)
Ce n'est pas en améliorant la bougie que l'on a inventé l'ampoule...

Eléphant du PHP | 185 Messages

22 juin 2008, 16:21

(je ne supporte d'ailleurs pas de voir des codes avec un if() qui récupère le résultat d'une requête, suivi d'un do/while sur la même condition, alors que le while évite cette redondance).
Ceci permet d'utiliser à bon escient les valeurs de retour des fonctions fetch_* !

Pour ma part, j'utilise des foreach() pour les tableaux (c'est fait pour, c'est optimisé pour ça).
Sinon des if () do { ... } while() pour les résultats de requêtes.
Et enfin des for pour les autres cas. Je n'utilise jamais de while.

Mammouth du PHP | 1668 Messages

22 juin 2008, 16:32

C'est un débat, j'ai le droit, ça va vous parraitre idiot mais c'est vrai, c'est en fonction de ce que l'on veux obtenir :

Si ça vient d'une BDD j'utilise while, les tableaux foreach et les boucles pour traiter/lister des éléments j'utilise for...

Par contre pour les boucles infini je préfert utiliser for que while...

Je n'ai aucunes preuve à ce sujet, je vous énnonce juste mon mode opératoire, c'est une question d'habitude, j'ai apprit comme ça...
"À ceux qui poursuivent leurs rêves et se spécialisent dans l'impossible" Joseph Kong

10 ans de PHP, déjà.

"moi jtrouve que katagoto il déchire!" Nagol

Avatar du membre
Modérateur PHPfrance
Modérateur PHPfrance | 10684 Messages

22 juin 2008, 16:52

(je ne supporte d'ailleurs pas de voir des codes avec un if() qui récupère le résultat d'une requête, suivi d'un do/while sur la même condition, alors que le while évite cette redondance).
Ceci permet d'utiliser à bon escient les valeurs de retour des fonctions fetch_* !
Ben les valeurs de retour, y en a que deux : soit un tableau lorsqu'il y a des résultats, soit FALSE en cas d'erreur ou s'il n'y a pas de résultats. Que je le teste avec un if() ou avec un while() ne fait pas une grande différence : si c'est faux, je rentre pas dans ma structure :)

Le principe du do/while c'est d'avoir 1 à N itération, tandis que c'est 0 à N pour le while. Du coup, c'est à mon sens un mauvais usage de cette boucle si tu dois tester au préalable le fait de devoir rentrer dedans. Soit tu dois exécuter au moins une itération de ta boucle (1..N) et tu utilises un do/while, soit tu ne sais pas si tu dois le faire ou pas (0..N) et c'est du while dont tu as besoin :)

Je suis sur qu'on peut enfoncer des clous avec un tournevis, mais c'est pas pour autant qu'il s'agit du bon outil pour le faire :)
Ce n'est pas en améliorant la bougie que l'on a inventé l'ampoule...

Mammouth du PHP | 2937 Messages

22 juin 2008, 18:28

Personnellement, je ne parlerais pas de préférence, mais de sémantique. Si j'utilise une boucle while (), c'est que mon raisonnement dit : "Tant que l'expression évaluée est vraie, j'indique des instructions à suivre" ; si c'est un foreach (), mon raisonnement dit : "Pour chaque itération du tableau en tant que variable valeur (ou couple de variables clé/valeur), j'indique des instructions à suivre" ; si c'est un for (), "Pour une variable i ayant une valeur comprise entre une valeur initiale et une valeur butoir (cette dernière pouvant être incluse ou non) et qui s'incrémente (ou se décrémente) de telle unité (pas forcément 1), j'indique des instructions à suivre".

Autrement dit, si j'ai un tableau dont la manipulation n'appelle pas à évaluer une expression, utiliser une boucle while (), c'est la détourner.

Autrement dit (si ce n'est toujours pas clair), basez-vous sur l'appellation de ces boucles : si elles s'appellent while, do... while, for ou foreach, ce n'est pas par manque d'inspiration de la part de l'équipe de PHP, mais pour décrire ce qu'elles font. ;)

En somme, c'est le même principe que pour le nom des éléments HTML ou des propriétés CSS.

Eléphant du PHP | 422 Messages

22 juin 2008, 18:47

Ca me plait toujours quand on parle de performances.
Quelles sont les différences de performances entre un for, un foreach, un while, ... ? 1/10e de secondes sur des boucles à 200 millions d'éléments ?
Si le problème de performance préoccupe tellement ton collègue, dis-lui de ne pas prendre un langage interprété comme le PHP, mais de bosser en C.

Ca me fait penser à un débat similaire sur "est-ce que i++ est plus efficace que i = i + 1 ?"
La réponse est oui sur les ordinateurs PDP-11 (ordi sur lequel a été créé le langage C) car le processeur du PDP possède l'instruction d'autoincrémentation et non sur la plupart des autres ordinateurs.

Cela dit, personnellement, j'utilise beaucoup le for sur les tableaux: parce que je m'y sens à l'aise. Parce que je faisais déjà des for en Pascal, en Basic, en Fortran, mais bien sûr évidemment uniquement quand les indices sont numériques et consécutifs. Et sinon les while (voire do ..while, mais j'aurais préféré un loop..until, qui fait la même chose, mais qui est plus explicite).
Enfin je n'utilise jamais le foreach qui n'existait pas avant PHP4 et qui peut être remplacé par while (list(...) = each).

ViPHP
ViPHP | 5924 Messages

22 juin 2008, 19:34

Ca me fait penser à un débat similaire sur "est-ce que i++ est plus efficace que i = i + 1 ?"
La réponse est oui sur les ordinateurs PDP-11 (ordi sur lequel a été créé le langage C) car le processeur du PDP possède l'instruction d'autoincrémentation et non sur la plupart des autres ordinateurs.
Théoriquement, cela doit donc aussi être le cas sur un x86, qui a l'instruction inc…
Par ailleurs, il ne m'étonnerait pas que les compilateurs modernes optimisent i = i + 1 en inc i…

Mammouth du PHP | 2937 Messages

22 juin 2008, 22:31

Enfin je n'utilise jamais le foreach qui n'existait pas avant PHP4 et qui peut être remplacé par while (list(...) = each).
Si l'on travaille encore sur des scripts PHP 3, passe encore ; mais, pourquoi utiliser la seconde boucle quand foreach fait le même travail en plus simple ? :-k C'est comme si, en PHP 5, on parcourait un dossier sans utiliser scandir () ! :shock:

Administrateur PHPfrance
Administrateur PHPfrance | 3131 Messages

22 juin 2008, 22:35

Il le fait surtout en beaucoup plus rapide.

Dans Typo3 par exemple, en remplaçant tous les while(list = each) par des foreach(), on gagne entre 8% et 10% de temps d'exécution. C'est absolument énorme.

Eléphant du PHP | 185 Messages

23 juin 2008, 00:12

[...]
Alors ça dépend après. Si je suis dans une optique MVC, alors cette boucle sera dans une fonction et un while() ça peut être cool pour faire le tableau.
On peut aussi vouloir afficher directement, et dans ce cas if() do ... While c'est bien parce qu'on peut afficher un truc avant les résultats et un truc après.

Je suis persuadé que la valeur de retour de mysql_fetch_* est bien mieux que mysql_num_rows() pour vérifier s'il y a des résulats :)
if ($machin = mysql_fetch_assoc($requete))
{
   echo '<table>
  <thead><tr><th>ID</th></thead>
  <tbody>';
  do
  {
    echo '<tr><td>'.$machin['id'].'</td></tr>';

  } while($machin = mysql_fetch_assoc($requete));

  echo '</tbody>
  </table>';
}
else
{
  echo '<p>Pas de résultat</p>';
}
Même dans une fonction en fait...
if ($machin = mysql_fetch_assoc($requete))
{
   $return = array();
  do
  {
    $return[] = $machin;

  } while($machin = mysql_fetch_assoc($requete));

  return $return;
}
else
{
  return false;
}
Enfin bon, avec PDO, on a fetchAll() donc plus besoin de ce bazar :D

Administrateur PHPfrance
Administrateur PHPfrance | 3131 Messages

23 juin 2008, 08:05

if ($machin = mysql_fetch_assoc($requete))
{
   $return = array();
  do
  {
    $return[] = $machin;

  } while($machin = mysql_fetch_assoc($requete));

  return $return;
}
else
{
  return false;
}
Étonnant que tu ne trouves pas ça plus lisible :
$return = array();
while ($ligne = mysql_fetch_assoc($requete)) {
  $return[] = $ligne;
}

return $return;
Car pourquoi renvoyer false s'il n'y a aucun résultat ? Rien ne le justifie, après tout :
- Pas de résultat = liste vide, c'est tout à fait normal. False devrait être alors réservé aux cas d'erreur.
- PHP est bien fait et false == array(), donc le test if (!ma_fonction()) sera toujours non vérifié s'il y a 0 résultats.

Dans l'ensemble c'est toujours une question de conception quand il y a ce genre de débat sur la "qualité" du code. Uniformiser la conception, homogénéiser les valeurs de retour, et le code est naturellement plus lisible déjà ;)

Mammouth du PHP | 514 Messages

23 juin 2008, 09:45

En ce qui me concerne, je tente, dès que je peux, de passer en foreach.

Uniforme, simple, rapide, et (presque) spécifique php, avant que tous les langages ne l'intègrent, évidemment ...

ViPHP
ViPHP | 4039 Messages

23 juin 2008, 09:50

pour ce qui concerne les opérations courtes sur des tableaux, j'utilise aussi array_walk() .
Mais qu'importe. (je suis ici - dernier petit projet)
Berze going social.