Aller au contenu principal

Module 7 – Gestion des erreurs & exceptions

Niveau 2 – PHP avancé


Objectifs

Ce module porte sur :

  • Distinguer erreurs et exceptions en PHP
  • Utiliser try / catch / finally pour gérer les exceptions
  • Créer des exceptions personnalisées et les utiliser dans la logique métier
  • Utiliser le logging (fichier de log, niveaux) pour le diagnostic

Théorie

Erreurs vs Exceptions

  • Erreurs (PHP traditionnel) : problèmes signalés par le moteur (notice, warning, fatal). On peut les convertir en exceptions avec un ErrorException ou les traiter avec un gestionnaire d’erreurs (set_error_handler).
  • Exceptions : objets lancés avec throw et attrapés avec try/catch. Elles permettent de gérer les cas exceptionnels de façon structurée.

En pratique, on privilégie les exceptions pour la logique métier (utilisateur introuvable, validation, échec d’une opération) et on log les erreurs techniques.


try / catch / finally

try {
$result = riskyOperation();
} catch (InvalidArgumentException $e) {
echo "Invalid argument: " . $e->getMessage();
} catch (Throwable $e) {
echo "Error: " . $e->getMessage();
} finally {
// Toujours exécuté (nettoyage, fermeture ressource)
closeConnection();
}
  • try : bloc où une exception peut être levée.
  • catch : capture un type d’exception (ou Throwable pour tout).
  • finally : exécuté dans tous les cas (succès ou exception), utile pour libérer des ressources.

Ordre des catch : du plus spécifique au plus général (ex. InvalidArgumentException avant Exception avant Throwable).


Lancer une exception

if ($age < 0 || $age > 150) {
throw new InvalidArgumentException("Invalid age: $age");
}

Messages clairs : mettre dans le message ce qui aide au diagnostic (sans exposer de données sensibles en production).


Exceptions personnalisées

Créer une classe qui extends Exception (ou une sous-classe comme RuntimeException, InvalidArgumentException).

class UserNotFoundException extends Exception {}

class EmailAlreadyInUseException extends RuntimeException {
public function __construct(string $email) {
parent::__construct("Email $email is already in use.");
}
}

Usage :

try {
$user = $repo->findByEmail($email);
if ($user === null) {
throw new UserNotFoundException();
}
} catch (UserNotFoundException $e) {
return "No account with this email.";
}

On peut ajouter des propriétés à l’exception (ex. code erreur, contexte) et les lire dans le catch.


Logging

Logger = enregistrer des messages (erreurs, infos, debug) dans un fichier ou un service, sans les afficher à l’utilisateur. En production on n’affiche pas les détails d’exceptions, on les logue.

Niveaux courants : debug, info, notice, warning, error, critical, alert, emergency.

PHP natif : error_log($message) écrit dans le log configuré (php.ini : error_log).

Exemple simple :

function logError(Throwable $e): void {
$msg = date('Y-m-d H:i:s') . " " . $e->getMessage() . " in " . $e->getFile() . ":" . $e->getLine();
error_log($msg);
}
try {
// ...
} catch (Throwable $e) {
logError($e);
echo "An error occurred."; // Generic message for the user
}

Frameworks / librairies : Monolog (PSR-3) est le standard en PHP pour des logs structurés (fichiers par niveau, rotation, etc.). Laravel utilise Monolog sous le capot.


Exemples

Exemple 1 : Validation avec exception

function setAge(int $age): void {
if ($age < 0 || $age > 150) {
throw new InvalidArgumentException("Age must be between 0 and 150.");
}
$this->age = $age;
}

Exemple 2 : Exception personnalisée avec contexte

class PaymentRefusedException extends Exception {
public function __construct(
string $message,
public readonly string $errorCode,
) {
parent::__construct($message);
}
}

Exemple 3 : try/catch + finally (ressource)

$f = fopen("data.txt", "r");
try {
$content = fread($f, 1024);
} finally {
fclose($f); // Toujours fermé
}

Bonnes pratiques

  1. Ne pas attraper sans traiter (éviter un catch vide). Au minimum logger.
  2. Messages d’exception clairs pour le debug, messages utilisateur génériques en production.
  3. Exceptions personnalisées pour les cas métier (utilisateur non trouvé, règle métier violée).
  4. finally pour libérer des ressources (fichiers, connexions).
  5. En production : ne pas exposer la stack trace à l’utilisateur ; la mettre dans les logs.

Quiz – Module 7

Q1. Quelle est la différence entre une erreur PHP et une exception ?
Q2. Dans quel ordre doit-on placer plusieurs blocs catch ?
Q3. À quoi sert le bloc finally ?
Q4. Comment créer une exception personnalisée ?
Q5. Pourquoi logger les exceptions en production au lieu de les afficher ?

Réponses

R1. Les erreurs sont signalées par le moteur PHP (notice, warning, fatal). Les exceptions sont des objets lancés avec throw et gérés avec try/catch, pour une gestion structurée des cas d’échec.

R2. Du plus spécifique au plus général (ex. InvalidArgumentException avant Exception avant Throwable).

R3. À exécuter du code dans tous les cas (succès ou exception), par exemple pour fermer un fichier ou une connexion (nettoyage).

R4. En créant une classe qui extends Exception (ou RuntimeException, InvalidArgumentException, etc.) et éventuellement en redéfinissant le constructeur.

R5. Pour ne pas exposer des détails techniques (fichiers, lignes, stack trace) à l’utilisateur et pour garder une trace côté serveur pour le diagnostic. On affiche un message générique à l’utilisateur.


Examen pratique

L’examen peut porter sur : écrire un try/catch avec une exception personnalisée, utiliser finally pour une ressource, et expliquer pourquoi on logue en production.


Suite

Module 8 – PHP & Base de données (SQL, PDO, requêtes préparées, injection SQL).