Gestion des erreurs en PHP : de try/catch aux solutions industrielles
\n\nChaque développeur PHP rencontre des erreurs. Le try/catch de base n'est que la partie émergée de l'iceberg. Dans cet article, nous allons explorer les techniques avancées de gestion des erreurs qui transformeront un code fragile en un système fiable, capable de réagir correctement à toute défaillance.
1. Plongée approfondie dans try/catch : le bloc finally et les catch multiples
\n\nLe try/catch standard est la base, mais beaucoup oublient le bloc finally, qui s'exécute toujours, qu'une exception ait été levée ou non. C'est l'endroit idéal pour fermer les ressources (fichiers, connexions à la base de données).
<?php\nfunction processFile(string $filename): void {\n $handle = fopen($filename, 'r');\n if (!$handle) {\n throw new \\RuntimeException("Impossible d'ouvrir le fichier : $filename");\n }\n \n try {\n // Traitement du fichier\n while (($line = fgets($handle)) !== false) {\n // ... logique de traitement\n }\n } catch (\\RuntimeException $e) {\n // Gestion spécifique des erreurs d'entrée/sortie\n error_log("Erreur de lecture du fichier : " . $e->getMessage());\n throw $e; // Relance vers le haut\n } catch (\\Exception $e) {\n // Gestion de toute autre exception\n error_log("Erreur inconnue : " . $e->getMessage());\n throw $e;\n } finally {\n fclose($handle); // Toujours fermer le fichier\n }\n}\n?>\n\nImportant : L'ordre des blocs catch a son importance. Les exceptions plus spécifiques (par exemple, \\RuntimeException) doivent venir avant les exceptions générales (\\Exception). Sinon, le bloc spécifique ne sera jamais exécuté.
2. Classes d'exceptions personnalisées : sémantique et hiérarchie
\n\nLes exceptions intégrées (PDOException, RuntimeException) sont souvent insuffisamment informatives. Créez votre propre hiérarchie d'exceptions pour séparer les erreurs par type et simplifier leur gestion.
\n\n<?php\n// Exception de base de l'application\nclass AppException extends \\Exception {}\n\n// Erreurs de validation\nclass ValidationException extends AppException {\n private array $errors;\n \n public function __construct(array $errors, string $message = "Erreur de validation") {\n parent::__construct($message, 422);\n $this->errors = $errors;\n }\n \n public function getErrors(): array {\n return $this->errors;\n }\n}\n\n// Erreurs d'accès\nclass AccessDeniedException extends AppException {\n public function __construct(string $message = "Accès refusé") {\n parent::__construct($message, 403);\n }\n}\n\n// Exemple d'utilisation\nfunction registerUser(array $data): void {\n $errors = [];\n \n if (empty($data['email'])) {\n $errors['email'] = 'Email obligatoire';\n }\n if (empty($data['password'])) {\n $errors['password'] = 'Mot de passe obligatoire';\n }\n \n if (!empty($errors)) {\n throw new ValidationException($errors);\n }\n \n // Logique d'inscription...\n}\n\ntry {\n registerUser(['email' => '']);\n} catch (ValidationException $e) {\n // Gestion spécifique : retourner un JSON avec les erreurs\n http_response_code(422);\n echo json_encode(['errors' => $e->getErrors()]);\n} catch (AccessDeniedException $e) {\n http_response_code(403);\n echo json_encode(['error' => $e->getMessage()]);\n} catch (AppException $e) {\n // Gestion générale pour toutes les autres erreurs de l'application\n http_response_code(500);\n echo json_encode(['error' => 'Erreur interne du serveur']);\n}\n?>\n\nConseil : Utilisez les codes HTTP (400, 403, 422, 500) comme codes d'exception — cela simplifie l'intégration avec une API REST.
\n\n3. Gestionnaire d'erreurs global : ErrorHandler et ShutdownHandler
\n\nToutes les erreurs ne peuvent pas être capturées avec try/catch. Les erreurs fatales (E_ERROR), les avertissements (E_WARNING) et les erreurs d'analyse