• 10 heures
  • Moyenne

Ce cours est visible gratuitement en ligne.

course.header.alt.is_video

Ce cours existe en livre papier.

course.header.alt.is_certifying

J'ai tout compris !

Mis à jour le 21/08/2023

Gérez vos cas d'erreur

Un bon programme ne plante jamais. Ça ne veut pas dire qu'il ne peut pas y avoir d'erreur, au contraire, ça arrive tout le temps ! Que ce soit un problème de saisie par un utilisateur ou un mauvais usage par un développeur.

L'essentiel est que le programme soit conçu pour réagir correctement en cas de mauvais usage ou de comportement inattendu. Avec un langage compilé, c'est assez facile à repérer, mais avec un langage interprété comme PHP, et dynamique de surcroît, alors c'est là qu'il faut vraiment se méfier.

Remontez un cas d'erreur avec le mot clé return

‌Voyons ensemble comment PHP gère les erreurs à travers cette vidéo. :)

‌Remontez un cas d'erreur avec le mot clé throw

Au lieu de gérer les cas d'erreurs avec des booléens, on va jeter une exception qui s'accompagne d'un message et qui peut s'accompagner d'un code d'erreur. Pour cela, il faut utiliser le mot clé throw.

<?php


/**
* @var string $text le contenu du message
* @return bool true en cas de succès
* @throw Exception on error
*/
function sendEmail(string $text): bool
{   
   if (/*on simule que l’envoie du message réussie*/ false)
   {
       // l’exception jetée avec son message et son code d’erreur
       throw new Exception('L\'envoi du mail a échoué', '22eb3737-3f43-497e-9912-a737975072ea');
   }   
  
   return true;
}
/**
* @var string $text le contenu du message
* @return bool true en cas de succès
* @throw Exception on error
*/
function sendNotification(string $text): bool
{
   if (/*on simule que l’envoie de notification échoue*/ true)
   {
       throw new Exception('L\'envoi de la notification a échoué', 'f3259929-61b2-44d0-a3d6-b855890c0726');
   } 
  
   return true;
}


/**
* @var string $text le contenu du message
* @return bool true en cas de succès
* @throw Exception on error
*/
function sendMessage(string $text): bool
{
   if (10 > strlen($text)) {
       throw new Exception('Le texte est trop court', '02bc3998-b9ff-431e-9058-8ab333ff7742');
   }


   sendEmail($text);
   sendNotification($text);
  
   return true;
}

if (!sendMessage('Hello, ici Greg "pappy" Boyington')) {
   // Avec les Exceptions, en cas d’erreur, ce code n’est plus jamais appelé contrairement à avant, avec l’envoie de booléen.
}

Que remarquez-vous ? Nous instancions des objets   Exception  avec un message et un code d'identification unique, pour qu'un programme puisse les distinguer.

Encore plus intéressant, regardez la fonction  sendMessage ! J'ai déplacé l'appel des méthodes   sendEmail  et   sendNotification  indépendamment de la vérification de longueur.

Attrapez les exceptions pour mieux les traiter

Pour attraper une exception, il faut utiliser une nouvelle structure : try { ... } catch (Exception $e) { ... }.

  • Entre les accolades du   try, on va mettre le code qui potentiellement peut jeter une exception. 

  • catch  se comporte comme une fonction, car entre parenthèses on mettra un argument typé   Exception, qui sera appelé en cas d’exception lancée dans le try.

  • Dans les accolades du   catch, le code à exécuter en cas d'interception d'une exception,  généralement un moyen de traiter l'erreur reçue.

‌Voyons ensemble comment intercepter les exceptions à travers cette vidéo.

On commence à avoir une belle gestion des erreurs, mais on peut faire encore mieux !  Exception  est une classe, donc... on peut l'étendre. 

Les exceptions natives de PHP

Dans PHP, par défaut il n'existe que la classe   Exception  . MAIS la librairie SPL (la même que pour le chargement automatique), qui est embarquée avec PHP, en propose d'autres. :)

Elle propose 2 classes qui étendent   Exception  :  LogicException  et RuntimeException. Ainsi qu'une dizaine d'autres qui découlent de ces deux-ci, que vous pouvez voir dans la documentation PHP

Alors pourquoi faire, déjà ?

Pour spécialiser votre gestion d'erreur à la manière de la programmation orientée objet ! Au lieu d'avoir un affreux  if...else  dans notre code,  try...catch  propose une structure permettant d'identifier la classe d'exception utilisée. 

Lorsque vous voulez expliquer à un développeur qu'il n'a pas correctement utilisé le code, et qu'il doit effectuer un changement dans son code, alors vous devez utiliser une LogicException. Si vous voulez exprimer une erreur suite à une saisie utilisateur, qui ne pourrait pas être détectée autrement que durant l’exécution, et donc qu'un simple message d'explication suffit, alors vous devrez utiliser une RuntimeException.‌ 

Vous savez ce qui serait encore mieux que d'utiliser ces deux exceptions ? Utiliser nos propres exceptions. 😎‌

Créez des exceptions personnalisées

En reprenant nos précédents exemples, nous pourrions remplacer les exceptions par des classes dédiées. Lorsque l'on va attraper les exceptions, plutôt que de regarder le code associé, on va demander à  catch  de regarder la classe de l'exception obtenue.

Nous avons 3 exceptions à créer :

  • une en cas d'erreur d'envoi de mail ;

  • une en cas d'erreur d'envoi de notification ;

  • et une en cas de texte trop court. 

Dans les 2 premiers cas, l'utilisateur ne peut rien y faire. Est-ce qu'il s'agit donc d'une  LogicException  ? Eh non, c'est un piège. Parce qu'ici le développeur ne peut rien y faire non plus. Nous sommes donc pour chacune dans le domaine des RuntimeException.

<?php


class EmailSendingErrorException extends RuntimeException
{
   public $message = 'Impossible d\'envoyer l\'email.';
}


class NotificationSendingErrorException extends RuntimeException
{
   public $message = 'Impossible d\'envoyer la notification.';
}


class ShortText extends RuntimeException
{
   public $message = 'Le texte fourni est trop court.';
}

C'est d'ailleurs très pratique de pouvoir y insérer un message par défaut. Il est temps de remplacer le code avec nos exceptions !

<?php


class EmailSendingErrorException extends RuntimeException
{
   public $message = 'Impossible d\'envoyer l\'email.';
}


class NotificationSendingErrorException extends RuntimeException
{
   public $message = 'Impossible d\'envoyer la notification.';
}


class ShortText extends RuntimeException
{
   public $message = 'Le texte fourni est trop court.';
}


/**
* @var string $text le contenu du message
* @return bool true en cas de succès
* @throw Exception on error
*/
function sendEmail(string $text): bool
{   
   if (/*envoie du message échoue*/ true)
   {
       throw new EmailSendingErrorException();
   }   
  
   return true;
}
/**
* @var string $text le contenu du message
* @return bool true en cas de succès
* @throw Exception on error
*/
function sendNotification(string $text): bool
{
   if (/*envoie de notification échoue*/ true)
   {
       throw new NotificationSendingErrorException();
   } 
  
   return true;
}


/**
* @var string $text le contenu du message
* @return bool true en cas de succès
* @throw Exception on error
*/
function sendMessage(string $text): bool
{
   if (10 > strlen($text)) {
       throw new ShortTextException();
   }


   try {
       sendNotification($text);
   } catch (NotificationSendingErrorException $e) {
       // Envoyez vous une alerte
       // pour vous prévenir que les notifications ne marche pas ;)
   } finally {
       // finally permet d'exécuter du code quoi qu'il arrive :)
       sendEmail($text);
       // si une exception est jetée par sendEmail,
       // Le return n'est jamais exécuté
       return true;
   }
}


try {
   sendMessage('Hello, ici Greg "pappy" Boyington');
} catch (ShortTextException $e) {
   echo $e->message;
} catch (EmailSendingErrorException $e) {
   echo 'Une erreur est survenue lors de l\'envoi du message, nos équipes ont été prévenues, veuillez réessayer plus tard';
} catch (Exception $e) {
   echo 'Une erreur inattendue est survenue, nos équipes ont été prévenues, veuillez réessayer plus tard';
}

Tester ce code

C'est pas top, ça ? On peut enchaîner les   catch  pour gérer les différents comportements maîtrisés et gérer les cas généraux. C'est à vous maintenant – utilisez des   Exceptions  dans le code fourni ci-dessous !

Exercez-vous

Dans cet exercice, je vous ai créé une codebase rassemblant tous les concepts que nous avons vus ensemble durant le cours POO.  Je vous encourage d’ailleurs à l’étudier.

Cependant, elle n’utilise pas encore les   Exceptions   😱 !

Pour faciliter la gestion d'erreur, remplacez les usages de la fonction trigger_error déjà présente dans le code, par l'usage des exceptions. Vous créerez un répertoire   Exceptions  dans le répertoire  src. Et à l'intérieur, vous créerez vos exceptions personnalisées.

Examinez le code et placez des   try...catch  aux endroits qui vous semblent importants.  

Le code se trouve sur la branche P3C6, et la correction sur la branche P3C6-correction

En résumé

  • PHP permet de gérer les erreurs avec les classes   Exception  en faisant remonter l'erreur à travers toute la pile d'exécution, grâce au mot clé  throw.

  • Les   Exceptions  offrent plus de finesse pour la gestion des erreurs avec le bloc  try...catch.

  • Créer vos exceptions vous donne plus de clarté dans votre code et dans le traitement des erreurs.

  • Il est possible d’enchaîner les catch pour gérer les différents types d’erreurs.

  • Le bloc finally placé après le(s) bloc(s) catch permet d’exécuter du code, qu’il y ait eu des erreurs, ou non.

Vous voilà maintenant avec toutes les clés en main pour faire de la programmation orientée objet ! Avant de valider tout ce que vous avez appris dans cette partie dans le dernier quiz, repassons sur ce que nous avons vu ensemble dans le chapitre suivant. 

Exemple de certificat de réussite
Exemple de certificat de réussite