[Débutant] POO : Les Exceptions

Eléphant du PHP | 189 Messages

27 janv. 2010, 21:43

(Re)Bonjour à tous,

Le net regorge de tutoriel , d'aide et de code source, je n'arrive malgré ça toujours pas à saisir le concept des exceptions.
Enfin, saisir est un grand mot, je comprend l'idée, le principe mais je n'arrive pas à trouver comment l'appliquer correctement.


Voici ce que j'ai pour le moment :
  • Index.php
    • Class MyException
    • Class Database
    • Class Session
    • Class User
    • Class Traduction
Class MyException :
Hérite d'exception, j'ai juste réécris la méthode getError();

Class Database :
J'utilise le pattern Multiton pour cette class, ce qui me permet d'instancier une seul fois la connexion vers plusieurs base de donnée.

Class Session :
Cette classe permet de créer une session (cookie/session) enregistrer cette session dans la db, vérifier la validité de la session et la supprimer

Class User :
Permet de charger un profil, le modifier, vérifier les accès.

Class Traduction :
Permet de traduire des chaînes "HOME" -> Accueil

Dans la class session et user je récupère dans le constructeur l'instance de ma base de donnée :
	public function __construct($user_id = 0) {
	
		global $site_config;

		$this->conn	= Database::getInstance($site_config['db_name']);
	

		$this->ip	= $_SERVER['REMOTE_ADDR'];

	}
La méthode getInstance est la suivante :
	public function getInstance($dbname) {
	
		if(! is_file(dirname(__FILE__)."/../config/db.inc.php")) {
			throw new myException ('DB_NOT_CONFIGURED');
			exit;
		}
		
		require_once(dirname(__FILE__)."/../config/db.inc.php");
		
		// On récupère les informations de connexion à la base de donnée
		if(empty(self::$dbinfo)) {
			self::$dbinfo = $db;
		}
		
		// Vérifie si la configuration pour $dbname existe
		if(array_key_exists($dbname,self::$dbinfo)) {
			// Si elle n'existe pas encore, crée une instance PDO vers $dbname
			if(!array_key_exists($dbname, self::$instance)) {
				self::$instance[$dbname] = new Database($dbname);
			}
		} else {
			throw new myException ('DB_NOT_CONFIGURED');
		}
		
		return self::$instance[$dbname];
	
	}
Maintenant que le décor est planté, je voudrais savoir comment vous verriez la chose ?

J'aimerais récupérer l'erreur de connexion lors de l'instanciation de ma class database, et afficher l'erreur plus loin dans la page.

Le problème, c'est que si je peut utiliser le try catch sur mon new database il faut aussi penser que le new user et new session auront eux aussi une erreur..

J'ai donc (après avoir été sur le chan irc) codé ceçi :
<?php
define('INDEX',true);

// Inclusion de tout les fichiers
include_once("includes/myexception.class.php");
include_once("includes/traduction.class.php");
include_once("includes/database.class.php");
include_once("includes/session.class.php");
include_once("includes/user.class.php");
include_once("config/config.inc.php");

define('DB_PREFIX',$site_config['db_prefix']);


?>
<a href="?con=0">Connexion (bad)</a> - <a href="?con=1">Connexion (good)</a> - <a href="./exemple.php">Reload</a> - <a href="?logout">Logout</a>
<?
// Instanciation de la class database
try {
	$www	= Database::getInstance("vfarena_com");


// Instanciation de la class Session. On lui passe un numéro de page en paramètre $page

	$page		= 1; 	// index.php
	$session	= New siteSession($page);
	$_SESSION['login_attempt'] = 0;
	
// Instanciation de la class Utilisateur
	$user		= New siteuser();
	
	// Demande de connexion
	if(isset($_GET['con'])) {
		
		$password = ($_GET['con'] == 1)? "123456": "12356";
		
		try {
			$user->connect("Admin",$password);
			// Crée une session
			$session->create($user->id,true);
		}
		catch (myException $e) {							/* Pourquoi ici créer un LoginException ?? */
			echo "<br/>Une Exception à été gérée :<br/><b>Error :</b> L'utilisateur n'a pas pu être connecté<br/><b>Motif :</b> ".$e->getError();
		}
	}
	
	// Demande de logout
	if(isset($_GET['logout'])) {
		$session->destroy();
	}

	$user->loadProfil($session->getUserId());
// Instanciation de la class Traduction

	try  {
		$traduction = new traduction($user->lng);
	}
	catch (myException $e) {
			echo "<br/>Une Exception à été gérée :<br/><b>Error :</b> Instanciation de la class Langue<br/><b>Motif :</b> ".$e->getError();
	}
	

	if($user->id != 0) {
		echo "<br/>Vous êtes connecté ".$user->pseudo;
	} else {
		echo "<br/>Vous n'êtes pas connecté";
	}
}
catch(MyException $e) {
	echo "Une Exception à été gérée : <br/><b>Error :</b> ".$e->getError()."<br/><b>Code :</b> ".$e->getCode();
}
?>
Mon premier try catch englobe l'ensemble des autres class, et donc l'erreur ne peut se produire qu'une fois ce qui règle le problème.

Mais maintenant dans le code forcément, si j'apelle $user ou $session , j'aurais une erreur car la class n'existe pas.

Je ne sais donc pas comment coder ça proprement en respectant les règles ..

Auriez-vous le temps pour me donner un coup de pouce ?

Pour terminer quelques questions :
1) On ma dit que je pouvais utiliser les exceptions pour les erreurs utilisateurs , est-ce une bonne méthode ?
2) On m'a aussi dit que je pouvais créer une class exception pour presque chaque exception que je veux gérer (Exemple : UserException, DatabaseException, SessionException etc)
3) Comment savoir ou et quand utiliser un try catch et générer une exception ? même question sur comment savoir ou la gerer ?

Si jamais vous avez des liens, et des commentaires sur mon code n'hésitez pas merci !!

ViPHP
ViPHP | 5462 Messages

27 janv. 2010, 21:47

hello, ta quelle version de php, si ta la 5.3+ tu peux t'orienter vers les namespace pour gerer tes exceptions,

par contre niveau de ton code les try sont beaucoup trop grand

Eléphant du PHP | 189 Messages

28 janv. 2010, 10:13

hello, ta quelle version de php, si ta la 5.3+ tu peux t'orienter vers les namespace pour gerer tes exceptions,
La version 5.3 ;-)
par contre niveau de ton code les try sont beaucoup trop grand
Justement, c'est la qu'est la question comment verriez-vous ce code ?

ViPHP
AB
ViPHP | 5818 Messages

28 janv. 2010, 15:17

hello, ta quelle version de php, si ta la 5.3+ tu peux t'orienter vers les namespace pour gerer tes exceptions,
La version 5.3 ;-)
Attention toutefois niveau portabilité de ton script. La plupart des mutualisés proposent actuellement une version php < 5.3

ViPHP
ViPHP | 5462 Messages

28 janv. 2010, 15:29

hello, ta quelle version de php, si ta la 5.3+ tu peux t'orienter vers les namespace pour gerer tes exceptions,
La version 5.3 ;-)
Attention toutefois niveau portabilité de ton script. La plupart des mutualisés proposent actuellement une version php < 5.3
OVH est sur 5.3.1

mais je suis d'accord avec toi faut attendre un peu quand même.

Eléphant du PHP | 189 Messages

28 janv. 2010, 16:27

Oui, l'hébergeur ou je suis propose php 5.3 mais, je ne sais toujours pas comment gérer ça ?

ViPHP
AB
ViPHP | 5818 Messages

28 janv. 2010, 16:41

@stealth35
Oui effectivement quand je parle portabilité, cela veut dire qu'à priori on ne sait pas quel hébergeur on va utiliser. La plupart des mutualisés pro ont des versions php5 >= 5.2 dont quelques uns >= 5.3.

Sur le plus connu des gratuits (free), c'est encore du 5.1.3 mais on est d'accord que c'est à exclure pour un site à vocation professionnelle.

Donc à l'heure actuelle je dirais qu'il est assez cohérent, niveau portabilité, d'utiliser 5.2 :wink:

ViPHP
ViPHP | 5462 Messages

28 janv. 2010, 16:46

Oui, l'hébergeur ou je suis propose php 5.3 mais, je ne sais toujours pas comment gérer ça ?
pour ton instance Database
tu peux simpelement faire un try du genre
try {
    $www    = Database::getInstance("vfarena_com");
}catch(MyException $e){
    exit("Une Exception à été gérée : <br/><b>Error :</b> ".$e->getError()."<br/><b>Code :</b> ".$e->getCode());
}
puisque de toute façon le reste dépens de ca (tu peux utiliser getMessage() pour afficher ca aussi) : exit($e->getMessage());

ensuite je doute de faire des exceptions partout, comme:
try  {
    $traduction = new traduction($user->lng);
}
catch (myException $e) {
    echo "<br/>Une Exception à été gérée :<br/><b>Error :</b> Instanciation de la class Langue<br/><b>Motif :</b> ".$e->getError();
}
ca plus a l'interrieur de la classe elle meme de gere se genre d'erreur, le problème c'est que tu peux avoir plusieurs erreur dans le code lui même, et c'est pas l'exeption qui va te dire ou.

ViPHP
ViPHP | 5462 Messages

28 janv. 2010, 16:47

@stealth35Sur le plus connu des gratuits (free), c'est encore du 5.1.3 mais on est d'accord que c'est à exclure pour un site à vocation professionnelle.
ouai Free c'est l'horreur, c'est le IE6 des mutu :mrgreen:

Eléphant du PHP | 189 Messages

29 janv. 2010, 16:07

Merci pour ra réponse stealth35 :
ca plus a l'interrieur de la classe elle meme de gere se genre d'erreur, le problème c'est que tu peux avoir plusieurs erreur dans le code lui même, et c'est pas l'exeption qui va te dire ou.
Je suis d'accord que gérer une exception, ne veut pas forcément dire : "Afficher une erreur"

Mais si c'est le cas , comment puis-je gérer l'exception dans ma class (Instanciée avant le header, car j'en ai besoins pour traduire le titre par exemple) et afficher le message d'erreur dans le body par exemple ?

C'est la que je suis perdu.. :-(

En php, vu qu'on n'a pas accès au code, le seul moyen de gérer ça convenablement (je parle de gérer l'exception de la class dans la class elle même) c'est d'utiliser des templates..
Qui me permettrais d'afficher l'erreur ou je veux:-(

Mais j'commence la POO donc, les templates ça sera juste pour après.

Merci

Eléphanteau du PHP | 16 Messages

29 janv. 2010, 16:17

Salut et si tu plaçais des
throw new Exception
dans ton code et que tu les récupérai dans le catch avec un beau template visuel ??

Par exemple :
$tab = array();
function inverse($x) {
    if (!$x) {
        throw new Exception('Division par zéro.');
    }
    else return 1/$x;
}

try {
    echo inverse(5) . "\n";
    echo inverse(0) . "\n";
	
} catch (Exception $e) {
    $tab['erreurs'][] .= $e->getMessage();
}

echo '<br />Bonjour le monde !<br />';
// Continue execution

// template erreur
echo print_r($tab['erreurs']);
Une partie de la source : http://php.net/manual/fr/language.exceptions.php.

Même si une erreur est rencontrée, le code continuera, à la rigeur tu te fait un tableau avec ces exceptions que tu "déballe" là ou tu veux dans ton body pour afficher l'erreur ?? Ou j'ai pas bien pigé ? ^^

Ou sinon tu peut toujours catcher l'erreur, lorsqu'elle arrive tu redirige avers un page d'erreur qui t'affiche celle-ci. 8-|

ViPHP
ViPHP | 5462 Messages

29 janv. 2010, 16:41

tu peux mettres les erreur dans le buffer avec ob_start()
http://php.net/manual/fr/function.ob-start.php