T: / Corrigés des challenges / PHP
Le while en PHP : sécurité, structure classique et avancée.
Au programme de ce corrigé :
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
}
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 !
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.
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);
}
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é.
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 :
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 :
Other content to discover
Corrections, challenges, news, technical monitoring... no spam.