Les derniers articles
PHP 5 et la gestion des exceptions
Date :: 2004-05-18
Last Updated :: 2004-08-03
Introduction
Dans cet article, nous allons étudier, le plus en détail possible, une des nouvelles fonctionnalités caractérisant PHP 5,
les exceptions.
En effet, PHP 5 fournit une nouvelle méthode très pratique pour la gestion des erreurs.
Le principe est simple et consiste en l'utilisation d'une classe de bas niveau (Exception)
disposant de cinq méthodes permettant de récuperer des informations sur les erreurs.
L'intéret majeur de cette classe est que ses fonctionnailités peuvent être étendues grâce à la notion d'héritage de la
Programmation Orientée objet, c'est ce que nous verrons dans les deux derniers paragraphes de cet article.
La classe Exception
Exception est une classe de bas niveau fournie par PHP 5
disposant des variables et méthodes membres suivantes :
Les variables
Les 3 variables membres suivantes sont protégées et ne pourront donc être réecrites qu'à l'intérieur d'une classe étendant les fonctionnalités de la classe Exception. Toute tentative d'accès ou de modification de ces variables en dehors de ce contexte provoquera une erreur.
- Exception :: message - Le message d'erreur qui sera passé en paramètre au constructeur de la classe Exception.
- Exception :: line - La ligne où s'est déroulée l'erreur.
- Exception :: file - Le nom du fichier où s'est déroulée l'erreur.
Les méthodes
Les 5 méthodes membres suivantes sont publiques et sont donc accessibles dans tous les contextes, du moment qu'un objet Exception a été instancié.
- Exception :: getMessage() - Cette méthode renvoie le message d'erreur qui sera passé en paramètre au constructeur de la classe Exception.
- Exception :: getLine() - Cette méthode renvoie la ligne où s'est déroulée l'erreur.
- Exception :: getFile() - Cette méthode renvoie le nom du fichier où s'est déroulée l'erreur.
-
Exception :: getTrace() - Cette méthode renvoie un tableau associatif contenant les informations suivantes :
.
- file - Le fichier où s'est déroulée l'erreur
- line - La ligne où s'est déroulée l'erreur
- function - La fonction concernée
- class - La classe concernée
- type - Type d'appel de la méthode (statique :: ou dynamique ->)
- args - Tableau contenant les arguments passés à cette méthode
- Exception :: getTraceAsString() - Cette méthode renvoie les mêmes informations que la méthode getTrace(), mais sous la forme d'une chaine de caractère au lieu d'un tableau.
Utilisation de la classe Exception
Création d'une méthode gérant une exception en cas d'erreur
Nous allons créer une classe très basique, nommée Machin, comprenant une unique méthode membre destinée à ouvrir un fichier en lecture.
Si l'ouverture de ce fichier s'avère impossible, nous lèverons une exception.
On notera l'utilisation du nouveau mot clé throw.
class Machin {
public function OpenFile($file) {
// On tente d'ouvrir le fichier $file.
if(!@fopen($file, 'r')) {
// Impossible !! on lève une exception.
throw new Exception ('Impossible d\'ouvrir ' . $file);
}
}
}
?>
Usage de l'exception
Nous allons instancier un objet Machin et tenter d'ouvrir un fichier avec la méthode Machin :: OpenFile().
Si le fichier est impossible à ouvrir, on affichera le message d'erreur renvoyé par l'exception.
Pour ce faire, il faut utiliser la nouvelle fonctionnalité de PHP 5, les try{} catch{}.
try{}
tentera d'apeller la méthode Machin :: OpenFile().
Si aucune exception n'a été levée dans la classe Machin, le code s'execute normallement.
catch{}
récupérera le résultat de l'exception et l'assignera à un objet.
On pourra donc se servir des méthodes de la classe Exception pour afficher l'erreur.
class Machin {
public function OpenFile($file) {
// On tente d'ouvrir le fichier $file.
if(!@fopen($file, 'r')) {
// Impossible !! on lève une exception.
throw new Exception ('Impossible d\'ouvrir ' . $file);
}
}
}
// -------------------------------------------------------------------------
// Nouvelle instance de la classe Machin
$O = new Machin;
// Utilisation des try{} catch{}
// On teste la méthode Machin :: OpenFile()
try {
$O -> OpenFile('truc-qui-n-existe-pas');
}
// Une exception a été levée, on affiche le message d'erreur via la méthode Exception :: getMessage()
catch (Exception $e) {
echo $e -> getMessage();
// ON aurait pu également se servir des autres méthodes proposées par la classe Exception :
// echo $e -> getLine(); // affichera le numéro de ligne de l'erreur.
// echo $e -> getFile(); // affichera le nom du fichier où s'est deroulée l'erreur.
}
?>
Création de votre propre classe gérant les exceptions
Au cas où vous en doutiez encore, la POO est vraiment magique :) .
Grâce à l'héritage, il est en effet possible d'étendre les fonctionnailités de la classe Exception,
nous allons voir comment.
En partant de ce principe, il devient très aisé de créer son propre gestionnaire d'erreur personnalisé,
avec par exemple des possibilités comme enregistrer les erreurs rencontrées dans un fichier ou une base de données,
envoyer des emails aux administrateurs, etc.
Votre propre classe
Pour démontrer la possibilité d'extension de la classe Exception,
nous allons créer notre propre classe qui ajoutera deux nouvelles méthodes membres.
La première sera chargée de récupérer la date et l'heure de l'erreur,
la seconde retournera un message d'erreur complet et formaté selon nos besoins.
Vous pouvez bien sur laisser libre cours à votre imagination pour modifier cette classe selon vos besoins,
c'est la un des intérets majeurs de la POO, qui seule, permet de réaliser tous ca,
notamment grâce à la notion d'héritage.
NOTE : Vous devez obligatoirement rapeller le constructeur le la classe Exception
à l'intérieur du constructeur de la classe censée étendre les fonctionnalités de cette dernière.
class MyException extends Exception {
// Constructeur de la classe.
// Il faut bien penser à rapeller le constructeur de la classe Exception.
public function __construct($msg) {
parent :: __construct($msg);
}
// Pour le fun, on ajoute une méthode qui récupère l'heure de l'erreur.
public function getTime() {
return date('Y-m-d H:i:s');
}
// Méthode retournant un message d'erreur complet et formaté.
public function getError() {
// On retourne un message d'erreur complet pour nos besoins.
$return = 'Une exception a été gérée :<br/>';
$return .= '<strong>Message : ' . $this->getMessage() . '</strong><br/>';
$return .= 'A la ligne : ' . $this->getLine() . '<br/>';
$return .= 'Dans le fichier : ' . $this->getFile() . '<br/>';
$return .= 'Il était : ' . $this->getTime();
return $return;
}
}
?>
Utilisation
L'utilisation ne nécessite pas de commentaire particulier, elle est la même que pour l'exemple précédent ormis le fait qu'on assigne l'objet à la classe MyException et non plus à la classe Exception et que l'on apelle la nouvelle méthode MyException :: getError() que l'on vient de créer.
class MyException extends Exception {
// Constructeur de la classe.
// Il faut bien penser à rapeller le constructeur de la classe Exception.
public function __construct($msg) {
parent :: __construct($msg);
}
// Pour le fun, on ajoute une méthode qui récupère l'heure de l'erreur.
public function getTime() {
return date('Y-m-d H:i:s');
}
// Méthode retournant un message d'erreur complet et formaté.
public function getError() {
// On retourne un message d'erreur complet pour nos besoins.
$return = 'Une exception a été gérée :<br/>';
$return .= '<strong>Message : ' . $this->getMessage() . '</strong><br/>';
$return .= 'A la ligne : ' . $this->getLine() . '<br/>';
$return .= 'Dans le fichier : ' . $this->getFile() . '<br/>';
$return .= 'Il était : ' . $this->getTime();
return $return;
}
}
// --------------------------------------------------------------------------------------------
class Machin {
public function OpenFile($file) {
// On tente d'ouvrir le fichier $file.
if(!@fopen($file, 'r')) {
// Impossible !! on lève une exception via la classe MyException et non plus Exception.
throw new MyException ('Impossible d\'ouvrir ' . $file);
}
}
}
// ---------------------------------------------------------------------------------------------
// Nouvelle instance de la classe Machin
$O = new Machin;
// Utilisation des try{} catch{}
// On teste la méthode Machin :: OpenFile()
try {
$O -> OpenFile('truc-qui-n-existe-pas');
}
// Une exception a été levée, on affiche le message d'erreur complet via la méthode MyException :: getError()
catch (MyException $e) {
echo $e -> getError();
}
?>
Gérer toutes les erreurs grâce aux exceptions
Il est possible , en réecrivant le gestionnaire d'erreur de PHP, de lever des exceptions sur tous les types d'erreur rencontrés,
erreurs fatales, avertissements (warning), notices, etc.
** Merci a Gabriel pour cet exemple.
La classe gérant les exceptions
/**
* RuntimeException encapsule une erreur (E_WARNING, E_NOTICE, ...) PHP dans un objet héritant de Exception
* @version: 1.0.0
* @Date:
* @author: Frédéric LECOINTRE<frederic.lecointre@burnweb.net>
*
* @TODO:
*/
class RuntimeException extends Exception {
/**
* ## SYSTEM METHODS ##
*/
/**
* Context d'éxécution fournit par PHP
* @var: array
* @access: protected
* @since: 1.0.0
*/
protected $_context = array();
/**
* Construit un objet RuntimeException
* @param: $levelException as integer(PHP_ERRORS_CONSTANTS) -> Le niveau de l'exception
* @param: $stringException as string -> La description de l'exception
* @param: $file as string -> Le nom du fichier où l'erreur s'est produite
* @param: $line as integer -> La ligne du fichier où l'erreur s'est produite
* @param: $context as array -> Le context d'éxécution fournit par le gestionnaire d'erreur
* @access: system
* @return: void
* @throws:
* @since: 1.0.0
*/
function __construct($level, $string, $file, $line, $context){
parent::__construct($string);
// on modifie la ligne et le fichier pour ne pas avoir la ligne et le fichier d'où l'exception est levée
$this->file = $file;
$this->line = $line;
$this->_level = $level;
$this->_context = $context;
} // end function __construct($level, $string, $file, $line)
}//end class
?>
Fonction de remplacement du gestionnaire d'erreur natif de PHP
/**
* Remplacant le gestionnaire d'erreur natif PHP. IL permet de lever une exception capturable dans un bloc catch
* pour les fonction/methode ne levant pas d'exception.
* @param: $level as integer(PHPErrorConstant) -> Niveau de l'erreur PHP
* @param: $string as string -> Description de l'erreur
* @param: $file as string -> Chemin d'accés au fichier dans lequel l'erreur s'est produite
* @param: $line as integer -> Ligne de $file où l'erreur s'est produite
* @param: $context as array -> Un contexte d'éxécution fournit par PHP
* @access: system
* @return: void
* @since: 1.0.0
* @author: Frédéric LECOINTRE<frederic.lecointre@burnweb.net>
* @TODO:
*
*/
function myErrorHandler($level, $string, $file, $line, $context){
throw new RuntimeException($level, $string, $file, $line, $context);
}//end function myErrorHandler($level, $string, $file, $line, $context)
?>
La classe de test
class Machin {
public function OpenFile($file) {
try{
// Ici une erreur: il manque le deuxieme parametre pour fopen().
// Une erreur E_WARNING va être déclenchée
fopen($file);
}
catch(Exception $e){
throw $e;
}
}
}
?>
Exemple 1
$O -> OpenFile va déclencher une erreur qui ne sera pas capturée dans le bloc catch car ce n'est pas une exception.
C'est le comportement normal de PHP.
Voilà la sortie:
Warning: fopen() expects at least 2 parameters, 1 given in /var/test/RuntimeException.psh on line 80
$O = new Machin();
try{
$O -> OpenFile('truc-qui-n-existe-pas');
}
catch(Exception $e){
echo $e;
}
?>
Exemple 2
$O -> OpenFile va déclencher une erreur qui sera capturée dans le bloc catch.
On redéfinit le gestionnaire d'erreur
avec notre gestionnaire myErrorHandler qui levera une RuntimeException pour toutes les erreurs.
Attention, les erreurs qui habituellement ne sont pas transmises au gestionnaire d'erreur utilisateur
ne le sont pas plus. En clair, tout ce qui est dit dans le manuel à propos de
set_error_handler() reste vrai ici.
Voilà la sortie:
exception 'RuntimeException' with message 'fopen() expects at least 2 parameters, 1 given' in /var/test/RuntimeException.psh:78
Stack trace:
#0 /var/test/RuntimeException.psh(78): myErrorHandler(2, 'fopen() expects...', '/var/test/Ru...', 78, Array)
#1 /var/test/RuntimeException.psh(78): fopen('truc-qui-n-exis...')
#2 /var/test/RuntimeException.psh(98): Machin->OpenFile('truc-qui-n-exis...')
#3 {main}
//Définition du gestionnaire d'erreur
set_error_handler('myErrorHandler');
$O = new Machin();
try{
$O -> OpenFile('truc-qui-n-existe-pas');
}
catch(Exception $e){
echo $e;
}
?>
Conclusion
Les exceptions, arrivées en PHP 5, apportent une classe de base solide et simple d'utilisation permettant de gérer les erreurs.
Avec toutes les fonctionnalités de la POO,
et notamment l'héritage, il devient relativement aisé de gérer de facon uniforme les erreurs tout au long d'un devellopement.
Je pense, vous en conviendrez comme moi, que PHP 5 n'a plus rien à envier à la plupart des langages orientés objet,
ce qui reste encore la méthode majeure de programmation.
Amusez vous bien ! :)
Fabrice Lezoray < fabrice AT scriptsphp.org >. Merci à Microtom et Gabriel pour leur contribution.
Trackback
Il n'y a pas de trackback recensé pour cet article.
Faire un trackback sur cet article http://classes.scriptsphp.org/Trackbackserver.PHP-5-et-les-exceptions, récupérer les trackback sur cet article