Pages :
Gérer les erreurs MySQL en PHP sans "or die"

Je viens de lire l'article et j'ai quelques remarques à y apporter :
* la solution proposée n'est pas si anodine que ça puisqu'on recrée une classe d'abstraction de données (autrement : on doit changer tout l'existant du site ... c'est pas rien)
* il a complètement ignoré PDO qui est là pour ça : il suffit d'étendre cette classe et cerise sur le gâteau, on n'est plus lié à MySQL
* try/catch existe et est là pour gérer ces cas de figure au lieu d'imbriquer des tas de if/else avec des @ pour masquer les erreurs

En clair, faut pas réinventer la roue, aller au plus simple et tout baigne Smiley smile
Hello,

Je suis assez d'accord. Annoncer la POO, comme secours sans utiliser les exceptions me parait bancal. Et quitte à faire, utiliser les outils natifs de PHP (PDO), parait naturel.

Bref, je plussoie l'oncle Tom, et suis même un peu étonné de trouver un article qui même s'il est propre, me parait assez dépassé.

Mes 2 centimes,

Tonio
Salut et merci pour les retours,

Je n'aime pas moi-même la partie POO (trop "basique"), mais il faut resituer : il faut un code simple et rapide à mettre en place pour illustrer le propos. C'est quand même un article que j'estime pour débutants, je ne voulais perdre personne avec une structure trop avancée.

Pour les exceptions, j'ai longuement hésité sachant que j'aurai la réflexion... et je suis resté sur ma position à fort potentiel trollesque.

Si vous voulez faire la suite du tuto pour un niveau supérieur, n'hésitez pas, Dew désespère de ne trouver personne pour en rédiger Smiley cligne
(ce n'est pas une pique ironique, personnellement je n'aurai pas le temps mais le besoin est réel)
Jerome A a écrit :
Salut et merci pour les retours,

Je n'aime pas moi-même la partie POO (trop "basique"), mais il faut resituer : il faut un code simple et rapide à mettre en place pour illustrer le propos. C'est quand même un article que j'estime pour débutants, je ne voulais perdre personne avec une structure trop avancée.

Pour les exceptions, j'ai longuement hésité sachant que j'aurai la réflexion... et je suis resté sur ma position à fort potentiel trollesque.

Si vous voulez faire la suite du tuto pour un niveau supérieur, n'hésitez pas, Dew désespère de ne trouver personne pour en rédiger Smiley cligne
(ce n'est pas une pique ironique, personnellement je n'aurai pas le temps mais le besoin est réel)


On est d'accord sur la partie simple et rapide. Je comprends aussi le souhait de parler à un large spectre d'utilisateurs.

Et je pense pas que ton avis était trollesque mais tiraillé entre la volonté de rester simple et d'utiliser des éléments avancés.

Pour faire simple sans utiliser PDO ça aurait été dans ce cas d'étendre la classe MySQL. Depuis PHP 4.3 on peut utiliser l'équivalent objet de la lib mysqli. Il suffit de l'étendre pour ajouter ce qu'on veut.



class MySQLEvolved extends mysqli
{

  public function isValid()
  {
    //...
  }

  //...
}


Tu peux utiliser ton singleton pour stocker l'ID de la ressource et éviter d'avoir à réécrire la plupart des fonctions.

Avec PHP4 on pouvait difficilement se lancer dans de telles aventures mais depuis PHP5 on peut étendre un sacré paquet de choses. Mieux vaut privilégier cette voie : c'est d'autant plus formateur pour les lecteurs car ils comprennent du coup l'intérêt de la chose et seront davantage tenté de construire des architectures maintenables.

Les tutos un jour ... j'ai un site et d'autres bricoles à terminer Smiley cligne
Bonjour, j'ai fais les même remarques en privé à Jérome A.

Je trouve moins crade d'utiliser les exceptions pour gérer les erreurs, notamment l'erreur de connexion à mysql. Erreur qu'il faut obligatoirement gérer avec les exceptions dans le cas de PDO rien que pour ne pas voir ses données de connexion affichées aux yeux de l'utilisateur.

Ceci dit, utiliser les exceptions ne dispense pas de tester son code et donc de pouvoir récupérer localement tout ce qui est rattrapable CàD, dans ce tutoriel tout sauf la connexion à MySQL. Tout ça pour dire que la divergence ce situe au final sur 2 lignes Smiley smile .

Il reste que le tutoriel me parait tout de même bon.

@Oncle Tom, je ne comprend pas pourquoi il est nécessaire d'étendre les classes PDO ou Mysqli pour traiter les erreurs? C'est pour ne pas à avoir à trop modifier le code source? (Moi, je fais un catch et je traite directement). J'aimerai bien un exemple pour comprendre, si possible.

Aussi, dans le code :

header('HTTP/1.1 404 Not Found');
header('Status:404 Not Found');


est ce qu'il est utile de préciser les 2 lignes? Je ne trouve pas de sources claires à ce sujet.
Modifié par bzh (17 Mar 2009 - 13:45)
bzh a écrit :

@Oncle Tom, je ne comprend pas pourquoi il est nécessaire d'étendre les classes PDO ou Mysqli pour traiter les erreurs? C'est pour ne pas à avoir à trop modifier le code source? (Moi, je fais un catch et je traite directement). J'aimerai bien un exemple pour comprendre, si possible.


Si t'utilises ces classes brut de fonderie il n'y a que peu d'intérêt à les étendre. Tu mets ton try/catch lors de l'instanciation de l'objet.

Par contre si tu y greffes de nouvelles méthodes comme il le fait c'est bien. En étandant l'objet t'as pas besoin de redéfinir les méthodes. Ou tu les étends aussi en utilisant l'appel de la méthode parent.
a écrit :
Pour faire simple sans utiliser PDO ça aurait été dans ce cas d'étendre la classe MySQL. Depuis PHP 4.3 on peut utiliser l'équivalent objet de la lib mysqli. Il suffit de l'étendre pour ajouter ce qu'on veut.

Nous sommes d'accord, la création d'une classe perso est... historique (ou comment faire de l'objet avec php4, un régal Smiley sweatdrop ).

a écrit :
Et je pense pas que ton avis était trollesque

En fait si, mon avis trollesque concerne les exceptions, je trouve que c'est faire propre avec des manières crades.
Pour illustrer, j'ai reçu un MP (pardon à son auteur si j'ai mal compris, mais mon interprétation est ce que je redoute le plus -- interprétation que je vais volontairement exagérer) me disant grosso modo "on code sans se soucier initialement des erreurs, et on fait un bon gros try/catch pour tout gérer à la fin".
Bah non, ça pour moi ce n'est pas propre. Une erreur, elle est anticipée et elle se gère à l'instant t.
Hello,

Je suis assez d'accord avec les avis précédents. Depuis que j'ai découvert PDO, je trouve que c'est beaucoup plus pratique à utiliser.
JE me suis même offert un petit bonus en évitant les try/catch qui finissent par être lourds à écrire à force, en utilisant set_exception_handler. En utiliant également systématiquement la bufférisation de sortie par-dessus, quand il y a un problème de SQL on kill le script après avoir soigneusement inclus une page 503 valide qui s'excuse poliment pour le désagrément encouru.

Quoi qu'il en soit, le @ est définitivement une preuve de mauvaise programmation. Citation ironique de microsoft : il y a des erreurs mais mon client ne les voit pas donc je m'en fous.
Désolé mais ça me fait penser à ça. J'ai définitivement banni le @ et je ne m'en porte que mieux.
QuentinC a écrit :
Quoi qu'il en soit, le @ est définitivement une preuve de mauvaise programmation. Citation ironique de microsoft : il y a des erreurs mais mon client ne les voit pas donc je m'en fous.

Il n'est mentionné nulle part qu'on se fout des erreurs, ni qu'elles sont masquées, bien au contraire. Voir ci-après.

QuentinC a écrit :
JE me suis même offert un petit bonus en évitant les try/catch qui finissent par être lourds à écrire à force, en utilisant set_exception_handler.

Bah je ne vois pas la différence avec l'utilisation de @, même combat, masquer des messages que PHP affiche malgré nous.
Quelle que soit la technique employée (@, set_exception_handler, error_reporting(0)), le but est d'empêcher PHP de gérer lui-même la sortie d'erreur, pour la gérer nous-mêmes à sa place. La seule différence que j'y vois, c'est que @ est très localisé (uniquement pour l'instruction en cours), c'est pour ça qu'il a ma préférence.

Pour en remettre une couche, un échec de connexion à mysql pour cause d'indisponibilité du serveur, ce n'est pas une exception. Quand je fais un mysql_connect (ou un new PDO), je fais une demande polie, je ne vois pas pourquoi PHP se permet de m'insulter avec son message d'erreur (ou son exception). Il me retourne false (ou, si on fait de l'objet, un objet représentant la connexion mais dans un état invalide testable), ça me suffit, je sais gérer derrière.
L'exception, elle se justifie si par exemple je tente une requête sans avoir d'identifiant de connexion. Sous-entendu, je n'ai pas fait mes tests et je tente une action dans un contexte invalide.

Je sens qu'on va partir dans une grande discussion philosophique sur la POO, j'aurais aimé éviter ça...

Mon but, c'était déjà de ne plus voir "or die", j'espère que ce message-là est passé. Pour le reste, je pense avoir déjà justifié mes choix, il ne s'agit que d'UN exemple parmi tant d'autres pour effectuer sa gestion. Libre à chacun d'utiliser le modèle objet qu'il voudra et avec lequel il sera le plus à l'aise. Il manque sûrement cette ouverture dans le tuto, je plaide coupable sur ce point, mais j'estime qu'il s'agit là d'un aspect purement POO qui aurait sa place dans un tuto dédié, avec un lien "pour aller plus loin" dans le mien.
Pour @ c'est très simple. Avec exemple :

$dblink = @mysql_connect(...);

if (!is_resource($dblink))
{
  //...
}


Si c'est juste, l'exception te permet de connaître précisément l'erreur : timeout, base injoignable ou inexistante, mauvais mot de passe. PHP ne t'insulte pas : il te rend service.

Dans le cas où la fonction appelée peut générer plusieurs exceptions différentes, ça permet d'isoler proprement la source de l'erreur avec plusieurs catch successifs.

On est en train d'écrire le futur article "if/else et try/catch sont dans un bâteau" Smiley cligne
a écrit :
Si c'est juste, l'exception te permet de connaître précisément l'erreur

Je te dis comment je vois les choses si les exceptions n'existaient pas :
$link = new Mysql(...);
// ici, $link est un objet de type Mysql, dans un état interne
// ok ou non selon le succès ou l'échec de la connexion

// Ensuite, je teste l'état de l'objet
if (!$link->isOk())
{
    echo $link->getError();
}
else
{
    $link->select('base');
    ...
}

C'est du pareil au même, sauf que là j'ai l'impression de faire de la prog.
Je t'accorde que les exceptions ont des avantages (typage qui facilite la gestion notamment), mais j'ai déjà fait mon choix donc je vais être... lourd ^^

a écrit :
Dans le cas où la fonction appelée peut générer plusieurs exceptions différentes, ça permet d'isoler proprement la source de l'erreur avec plusieurs catch successifs.

Dans le cas où getError peut retourner plusieurs codes d'erreurs différents, ça permet d'isoler proprement la source de l'erreur avec plusieurs else successifs. Smiley ravi
(désolé, c'était trop tentant)

a écrit :
On est en train d'écrire le futur article "if/else et try/catch sont dans un bâteau"

Ben on n'est pas couché Smiley langue
Oui mais non dans tous les cas : tu laisses à ta classe le soin de faire un echo de l'erreur.
Et si on veut pas ? On est obligé de modifier ta classe.

L'exception permet de capturer tout ça avec une autre classe et de déléguer l'affichage ou le log de celle-ci en fonction de l'environnement d'utilisation (dev, production ou autre).

L'erreur ne regarde que le développeur.
Et les exceptions c'est aussi faire de la prog ... maintenable Smiley cligne

Ta solution est quand même relativement propre mais tout dépend avec quel niveau d'aisance tu veux te retrouver.
Oncle Tom a écrit :
Oui mais non dans tous les cas : tu laisses à ta classe le soin de faire un echo de l'erreur.

Heu... non, regarde bien le code, je suis bien en partie exploitation, le echo n'est pas dans la classe. On est vraiment dans un cas où try/catch et if/else agissent de la "même manière".

a écrit :
Et les exceptions c'est aussi faire de la prog ... maintenable

Oui, mais c'est le principe que je n'aime pas, ça fait genre "je croise les doigts pour que ça marche, advienne que pourra". Question de préférence uniquement, on peut très bien faire propre avec. Disons que c'est psychologique Smiley cligne
Salut,

alors déjà je tiens à dire que le tuto me plaît bien "en l'état". Smiley cligne

Jerome A a écrit :
Oui, mais c'est le principe que je n'aime pas, ça fait genre "je croise les doigts pour que ça marche, advienne que pourra". Question de préférence uniquement, on peut très bien faire propre avec. Disons que c'est psychologique Smiley cligne
Euh... effectivement on sent quand même un certain parti pris ! Smiley langue

Comme je n'utilise PHP quasiment que pour faire du web je n'ai jamais eu à pousser la programmation objet bien loin avec ce langage mais pour ce qui est du trio try catch finally je m'en sers en java et je m'insurge contre le "je croise les doigts pour que ça marche, advienne que pourra" : il permet entre autres de récupérer tous les types d'erreur et ce de manière propre et lisible, de sortir proprement de la boucle et de permettre plusieurs options de "récupération" en fonction du type d'exception, d'effectuer tout de même un traitement quoi qu'il ait pu se produire comme erreur, et surtout de propager (à l'aide de throw) ces exceptions aux méthodes appelantes qui, elles aussi bénéficient du trio try catch finally. Bref ! Que du bonheur !

Donc rien à voir avec du "croisage de doigts" mais bel et bien de la belle programmation comme on aime ! Smiley lol
IL faut bien se dire qu'on a introduit le concept des exceptions parce que ça apportait quelque chose à la programmation.
Je vais arrêter, je suis en train de nourrir le troll if/else vs try/catch. Pendant qu'on parle de java, à quand un débat sur la généricité et la surcharge d'opérateur ? Non bon OK, je sors.

a écrit :
Mon but, c'était déjà de ne plus voir "or die", j'espère que ce message-là est passé.

Oui, largement. En fait ce qui se passe c'est qu'ici tu as à faire à un public déjà convaincu, alors que tu vises un public plutôt débutant.

J'aurais bien vu ce genre de tuto sur le site du zéro : c'est simple, clair, bien expliqué, ça explique le problème depuis le début et c'est prévu pour le débutant. La plupart là bas ne jurent que par le fameux or die, qui est très tôt expliqué dans le tutoriel officiel, ça leur ferait du bien de lire un tuto tel que celui-ci.
Il se trouve que sur alsa, le niveau est plus élevé donc forcément, on pense tout de suite plus loin.
QuentinC a écrit :
Pendant qu'on parle de java, à quand un débat sur la généricité et la surcharge d'opérateur ? Non bon OK, je sors.
Effectivement il y a peu de chances qu'un tel débat ait lieu sur Alsa ! Smiley smile

QuentinC a écrit :
En fait ce qui se passe c'est qu'ici tu as à faire à un public déjà convaincu, alors que tu vises un public plutôt débutant.
Je pense que cela résume bien le sujet : Alsa s'adresse essentiellement aux débutants et même si des tutos sur la programmation objet en PHP par exemple seraient intéressants (bien qu'on s'éloigne à grand pas des standards du web et de l'accessibilité) il vaudrait mieux commencer selon moi par des choses plus basiques comme les formulaires et l'envoi de mails...
Salut Heyoan,
Je vais illustrer un peu mieux mon propos, je me rends compte qu'il manque un point dans le code donné plus haut.
Les exceptions, c'est bien quand on peut événtuellement faire une action non conforme.
$link = new Mysql(...);
// ici, $link est un objet de type Mysql, dans un état interne
// ok ou non selon le succès ou l'échec de la connexion

// Ensuite, je teste l'état de l'objet
if (!$link->isOk())
{
    echo $link->getError();
}
else
{
    $link->select('base');
    ...
}

Jusque là, j'ai pris mes précautions, donc pas d'exceptions. Maintenant, je ne fais pas le test :
$link = new Mysql(...);
// supposons que $link soit dans un état interne non-OK...

// je ne teste PAS l'état de l'objet
$link->select('base');
// BLAM ! Exception, donc try/catch

Là tout est logique. Alors maintenant, que faire ? Tester avant ou tenter le coup et rattraper l'erreur ensuite ?
Personnellement, je teste avant. Si vraiment je ne peux pas (boite noire), try/catch.
Je le répète, c'est purement perso comme décision et tu as le droit te t'indigner, mais try ça veut quand même dire "essayer". Au lieu de mettre la main sur la porte du four pour attraper la brulure, je vérifie la température.

Je vous avais bien dÿ que ma position avait un fort potentiel trollesque Smiley murf

Pour le public visé et la pertinence du tuto sur Alsa... voir le forum sur les langages serveur, pas un seul post sur mysql sans un or die. Croyants mais non-pratiquants ?

Et pour finir sur la difficulté, le débutant se sera arrété à la deuxième partie et aura testé proprement sa connexion avec un bon vieux if toujours aussi efficace.
Modifié par Jerome A (18 Mar 2009 - 09:38)
Jerome A a écrit :

Jusque là, j'ai pris mes précautions, donc pas d'exceptions. Maintenant, je ne fais pas le test :
$link = new Mysql(...);
// supposons que $link soit dans un état interne non-OK...

// je ne teste PAS l'état de l'objet
$link->select('base');
// BLAM ! Exception, donc try/catch

Là tout est logique. Alors maintenant, que faire ? Tester avant ou tenter le coup et rattraper l'erreur ensuite ?
Personnellement, je teste avant.


Mais personne n'a dit qu'il fallait faire ça Smiley sweatdrop . Lancer une exception alors qu'on peut éviter l'erreur n'a pas d'intérêt. A te lire, on dirait que ceux qui utilisent les exceptions font :


try{
//100 lignes de code
}

catch{
echo 'c\'est mort';
}
Salut bzh,
Ce que je veux dire, c'est presque :
a écrit :
Lancer une exception alors qu'on peut éviter l'erreur n'a pas d'intérêt

Je dis "presque" à cause du "lancer". Un module qui lance une exception parce que son état est incompatible avec la commande demandée, c'est bon, mangez-en. Ce que je n'aime pas, c'est de passer par cette exception au lieu de tester au préalable quand on en a les moyens.

Par conséquent, je trouve risible que new PDO lance une exception si la connexion échoue. L'action n'est pas illégale, ce qui le serait, ce serait de tenter une requete sur un objet PDO non connecté.

Et j'espère bien que personne ne fait des try sur 100 lignes de code Smiley cligne (je ne vois pas ce qui te fait penser ça, dans mon code le try catch n'aurait cerné que le $link->select, ce n'est peut-être pas clair...)
Jerome A a écrit :

Par conséquent, je trouve risible que new PDO lance une exception si la connexion échoue. L'action n'est pas illégale, ce qui le serait, ce serait de tenter une requete sur un objet PDO non connecté.


Oui, t'as pas tort, ça a sans doute était retenu parce que c'est un moyen pratique pour tester mais pas forcément logique.

J'ai l'impression que les tests en php relèvent de toute façon plus de la bidouille qu'autre chose tel truc qui renvoie false, l'autre throw et celui la 0... berk, berk, berk Smiley smile
Modifié par bzh (18 Mar 2009 - 11:38)
Pages :