Le while en PHP : bloqueur, condition d’arrêt et break

Le while en PHP : sécurité, structure classique et avancée.

→ Corrigé du Challenge : Vegeta combat ses ennemis

Au programme de ce corrigé :

Pourquoi utiliser un while ?

Dans ce challenge, on ne sait pas d’avance de combien de niveaux il faudra augmenter Vegeta pour qu’il puisse combattre un ennemi donné. On a donc des opérations à répéter (=> boucle) mais on ne sait pas combien de fois (=> tant que…), la structure while est donc la bonne structure à utiliser. Elle va permettre de répéter un ensemble d’instructions tant qu’une certaine condition n’est pas atteinte.

La structure de base est la suivante :

while(/* condition(s) d'arrêt */) {

   // Bloc d'instructions

}

Intégrer un bloqueur pour sécuriser son while en PHP

Mal utilisé, le while peut alors entraîner une « boucle infinie », c’est-à-dire que rien ne va arrêter le « tant que ». Le script va donc s’exécuter jusqu’à rencontrer le « max_execution_time » du serveur et provoquer une erreur fatale.

Quand on code un while, et qu’on n’est pas sûr du code qu’il contient, on peut intégrer un bloqueur. C’est-à-dire une variable qui va forcément « casser » le while à un moment donné pour éviter de se retrouver dans le cas de figure de la boucle infinie.

Exemple :

// Initialisation de mon bloqueur
$stop = 0;

while (/* condition(s) d'arrêt */) {

	// Mon code spécifique

	// Le code de mon bloqueur
	$stop++;
	if ($stop > 1000) {
		break;
	}
}

Le 1000 est ici arbitraire, à ajuster selon ton code. De cette façon, même si je mets plusieurs tentatives à bien structurer ma condition d’arrêt et ou le code à l’intérieur de mon while, je suis sûr de ne jamais rester dans une boucle infinie !

while classique en PHP

J’ai appris le while de cette façon, c’est à dire en mettant la condition d’arrêt dans les ( ) du while.

Dans le challenge DBZ_1, je parcours chaque ennemi, et j’augmente le niveau de Végéta tant que sa puissance n’est pas suffisante pour battre l’ennemi. Voici le code avec un while classique : (je garde volontairement le bloqueur)

// Une fonction pour calculer la puissance
function puissance(int $niveau, int $force): int
{
	return $niveau * $force;
}

// Code du challenge
$niveau = 1;

foreach ($ennemis as $ennemi) {

	$stop = 0;

	// La condition d'arrêt est ici :
	while (puissance($niveau, $force_vegeta) < $ennemi) {
		$niveau++;

		$stop++;
		if ($stop > 1000) {
			break;
		}
	}

	$force_vegeta += floor($ennemi / 10);
}

Pour s’assurer de ne pas rester dans une boucle infinie, il faut absolument qu’au moins 1 élément présent dans la condition d’arrêt soit altéré dans le bloc d’instructions du while { }. Sinon la condition d’arrêt ne change pas.

Ici, $niveau est incrémenté à chaque itération, donc la valeur retournée par la fonction puissance va bien changer, donc la condition d’arrêt évolue, donc on devrait bien « sortir » du while.

while true en PHP

Une autre façon d’écrire son while consiste à déplacer la condition d’arrêt dans le bloc d’instructions. On aura donc un while(true) { … } et obligatoirement une instruction break dans le while (différente de celle du bloqueur bien sûr).

Le bloqueur prend encore + d’importance dans la construction du while ici, car un while true sans break va forcément enclencher une boucle infinie.

Voici le code précédent, ajusté avec un while true : (volontairement sans le bloqueur)

$niveau = 1;

foreach ($ennemis as $ennemi) {

	while (true) {

		if (puissance($niveau, $force_vegeta) >= $ennemi) {
			break;
		}

		$niveau++;
	}

	$force_vegeta += floor($ennemi / 10);
}

Quelle structure while utiliser ?

Avec l’expérience, je préfère le while true, elle permet de voir explicitement ce qui va interrompre la boucle while. Et ça prend tout son sens quand on a plusieurs façons d’interrompre la boucle. Avec le while classique, on cumulerait les conditions avec des && ou des || alors que ces conditions peuvent n’avoir que peu de lien logique. Avec cette façon de faire, tout est structuré et clarifié.

Quelles différences avec la structure do while ?

PHP propose une structure similaire au while : do while.

On commence par le bloc d’instructions, puis la condition d’arrêt :

do {

   // Bloc d'instructions

} while (/* condition(s) d'arrêt */)

2 différences, dont une vraiment majeure :

  • Avec un do while, la vérification de la condition d’arrêt est effectuée après la première itération d’un bloc d’instructions. Ce qui veut dire que ce bloc d’instructions est toujours exécuté au minimum 1 fois. Avec un while classique, si la condition d’arrêt n’est pas respectée, le bloc d’instructions n’est pas du tout exécuté.
  • La lisibilité est inversée, on va d’abord lire le bloc d’instructions puis la condition d’arrêt.

Personnellement, je n’utilise presque jamais cette structure. Je préfère m’en tenir au simple while pour éviter de complexifier la lecture de mon code.

Le seul cas d’usage que je trouve intéressant avec le do while est quand on génère un élément dans le bloc d’instructions, qui est contrôlé dans la condition d’arrêt. Par exemple quand je cherche à créer des éléments uniques : (disons un code secret unique à founir lors d’une livraison par exemple)

// J'ai à ma disposition 2 fonctions : 
// generateCode() qui génère un code aléatoire, disons de 4 lettres majuscules
// codeEstDejaUtilise() qui retourne true ou false si le code est déjà utilisé

// Avec un while true
$code = generateCode();
while(true) {
   if (! codeEstDejaUtilise($code)) {
      break;
   }

   $code = generateCode();
}

return $code;

// --------

// Avec un do while
do {
   $code = generateCode();
} while (codeEstDejaUtilise($code));

return $code;

Comme je dois toujours au moins générer 1 code, le do while a toute sa légitimité ici.

On remarquera aussi que les conditions ne sont pas écrites pareilles :

  • Dans le while (true), je m’arrête si le code n’est pas utilisé
  • Dans le do while, je continue si le code est déjà utilisé

Conclusions

  • Un bloqueur peut permettre de sécuriser son while pour éviter la boucle inifinie tant qu’on est pas sûr de son écriture
  • while classique VS while true + break : Si on a 1 ou 2 conditions d’arrêt, c’est vraiment une histoire de préférences et de conventions à respecter. Si + de 2 conditions d’arrêt, je conseille vraiment un while true.
  • Le do while peut avoir un intérêt pour certains usages, sinon je conseille de ne pas mélanger les structures, encore une fois par soucis de cohérence dans une codebase et de lisibilité

Qui a codé ce superbe contenu ?

Keep learning

Autres contenus à découvrir


Ta newsletter chaque mois

Corrigés, challenges, actualités, veille technique... aucun spam.