Utiliser switch() pour gérer des processus

Voici une façon d’utiliser l’instruction switch présente sur de nombreux langages, notamment en PHP :

switch (false) {
   case doStep1(): print("Error at step 1"); break;
   case doStep2(): print("Error at step 2"); break;
   case doStep3(): print("Error at step 3"); break;
   default: print("Success!"); break;
}

Cette méthode permet notamment de gérer les retours en cas d’erreur lors du déroulement du processus. Les étapes vont être exécutées une à une et si l’une d’elles échoue (return false par exemple), le traitement associé à cette étape est exécuté puis le processus est terminé.
Si doStep1() retourne true, la comparaison avec le false du switch échoue et le programme tente avec le prochain case défini. Par contre, si doStep1() retourne false, la comparaison correspond (false == false) et le traitement associé au case est donc exécuté – en l’occurrence le traitement de l’erreur.

En somme, le fonctionnement n’est pas différent de :

if (doStep1()) {
   if (doStep2()) {
      if (!doStep3()) {
         print("Success!");
      } else {
         print("Error at step 3");
      }
   } else {
      print("Error at step 2");
   }
} else {
   print("Error at step 1");
}

ou encore de :

if (!doStep1()) {
   print("Error at step 1");
} else if (!doStep2()) {
   print("Error at step 2");
} else if (!doStep3()) {
   print("Error at step 3");
} else {
   print("Success!");
}

L’avantage de la notation en switch réside principalement dans sa lisibilité. En effet, chacune des notations précédente a au moins un défaut. Pour la première, il sont évidents : la cascade de conditions (indentation) et la séparation symétrique entre la condition et le traitement d’erreur (le traitement de l’étape 1 est à la fin, le message de succès est au milieu) entraînent une très mauvaise lisibilité du processus. Pour la deuxième, le processus reste lisible mais les conditions peuvent l’être moins puisqu’elles testent la non-validité de l’étape. Ainsi la compréhension des étapes est polluée par la négation de la condition : par le signe ! en préfixe dans l’exemple, mais éventuellement par des conditions plus tordues (!a || !b || !c…).
La structure en switch, pour peu qu’on la connaisse, offre une lisibilité adaptée au déroulement d’un processus : chaque étape se situe sur la même colonne, chaque traitement d’erreur ou de succès est proche de sa cause et les étapes sont lisibles. En faisant abstraction du langage en lui-même, la structure correspond à :

PROCESS:
   STEP1: ERROR1
   STEP2: ERROR2
   STEP3: ERROR3
   END: SUCCESS

Cette structure favorise également la décomposition de chaque étape en une fonction claire. Ainsi, au lieu d’avoir une accumulation de traitements mélangés comme c’est le cas lors de l’utilisation d’un if, la structure incite (en tout cas encourage) à nommer clairement chaque étape et à réaliser la fonction associée :

switch (false) {
   case enterLogin(): ... break;
   case enterPassword(): ... break;
   case validateForm(): ... break;
   case checkAuthentication(): ... break;
   ...
}

Lorsque quelqu’un relit le code, il peut très simplement comprendre le processus en lisant le nom de chaque fonction.

Enfin, le switch offre un léger avantage sur le if : l’instruction break. Cette dernière permet d’interrompre le processus à tout moment et peut éviter des constructions complexes. On peut par exemple écrire :

switch (false) {
   case doStep1():
      if (verbose == 0) break;
      print('Error');
      if (verbose == 1) break;
      print(error_msg());
      break;
   ...
   default:
      if (...) {
         break;
      }
      ...
}

Ce fonctionnement est moins naturel à réaliser avec un if.

Pour terminer, voici un exemple en syntaxe PHP d’une structure switch (false) qui mélange vérification et processus :

switch (false) {
   // checking if the process can be executed
   case doesTheUserWantToExecuteThisProcess():
      break;

   // checking some general conditions
   case isTheUserAuthenticated():
      redirectToLoginPage(); break;

   // checking variables
   case isPosted('title'):
      printError('The title is mandatory.'); break;
   case isPosted('text'):
      printError('The text is mandatory.'); break;
   case isPosted('category'):
      printError('The category is mandatory.'); break;

   // executing the process
   case connectToDatabase():
      printError('Database connection failed.'); break;
   case $article = Article::create(posted('title'), posted('text')):
      printError('The creation of the article failed!'); break;
   case moveArticleToCategory($article, posted('category')):
      printError('The category does not exist.'); break;
   default:
      printSuccess('Your article has been added to the category!');
}