10
votes

Comment devrais-je gérer les erreurs attendues? par exemple. "Ce nom d'utilisateur existe déjà"

Je suis en difficulté pour comprendre comment je dois concevoir les parties de manipulation des erreurs de mon code. J'ai récemment posé une question similaire sur la façon dont je devrais aller sur Codes d'erreur du serveur retourner à l'utilisateur, par exemple. 404 erreurs . J'ai appris que je devrais gérer l'erreur de la partie actuelle de l'application; semble assez simple.

Cependant, que dois-je faire lorsque je ne peux pas gérer l'erreur du lien actuel de la chaîne? Par exemple, je peux avoir une classe utilisée pour gérer l'authentification. L'une de ses méthodes pourrait être CreateUser ($ nom d'utilisateur, $ mot de passe) . éditer: Cette méthode retournera un identifiant d'utilisateur ou un objet utilisateur. dans cette fonction, je dois déterminer si le nom d'utilisateur existe déjà. Si cela est vrai, comment devrais-je alerter le code d'appel à ce sujet? Renvoyer NULL au lieu d'un objet utilisateur est d'une manière. Mais comment puis-je alors savoir ce qui a causé l'erreur?

Comment devez-vous gérer les erreurs de manière à ce que l'appel du code puisse trouver facilement ce qui a provoqué l'erreur? Y a-t-il un modèle de conception couramment utilisé pour ce type de situation?

edit: J'ai oublié de mentionner: j'utilise php.


résolu: Bien que de nombreuses personnes affirment que des exceptions ne doivent pas être utilisées dans cette situation, je suis arrivé à la conclusion que c'est la meilleure solution.

Premièrement, il n'y a pas d'alternative simple et élégante aux exceptions. (Je reconquête qu'il n'est pas possible sans un système intégré dans la langue ... Les exceptions sont déjà intégrées.)

Deuxièmement, en réponse aux "exceptions ne doit être utilisée que pour des situations exceptionnelles, ce n'est pas un" argument: " Quand j'appelle getfoo (), je m'attends à obtenir un foo. Si je ne comprends pas, c'est par définition un événement exceptionnel. " (via, pKainulainen )


0 commentaires

7 Réponses :


3
votes

Il y a quelques modèles courants:

1. Lancer un Exception . P>

2. Renvoie NULL ou FAUX et définissez une référence transmise à une erreur. E.g. P>

$userCreateError = NULL;
$res = createUser($user, $pass, $userCreateError);
if($res === NULL)
{
  // do something with $userCreateError
}


4 commentaires

Pourriez-vous développer ce que vous entendez par 'définir un objet d'erreur' s'il vous plaît? Merci!


Parmi ces trois, des exceptions semblent presque sur mesure pour traiter le type de scénarios décrits dans la question. Vous pouvez choisir et choisir comment gérer chaque événement exceptionnel en fonction de la classe et du message de l'exception.


@tehblanx - Je pense que je suis en désaccord. Le code doit renvoyer true sur le succès et false sinon. Idéalement, cela sera tous géré dans une classe et la classe elle-même peut gérer les problèmes découlant d'une inscription échouée.


@thetaiko - Je vois ce que vous dites, mais je pense que c'est trop limitant. 'False' ne dit que l'appelant que quelque chose a mal tourné sans plus de détails. Et si la conception spécifie que l'appelant devrait prendre un plan d'action lorsqu'il est confronté à un "Impossible de créer en raison d'une erreur de connexion de base de données" contre un différent pour "ne peut pas créer en raison d'un nom d'utilisateur en double?" Vous pouvez mettre en œuvre une sorte d'objet d'erreur à ce stade, mais je pense que des exceptions sont plus élégantes pour cette tâche.



0
votes

Vous pouvez retourner des entiers définis dans un fichier d'en-tête global avec des noms tels que Duplicate_user ou Invalid_password ou tout ce qui convient à votre utilisation. Ensuite, la fonction de l'appelant peut facilement vérifier ces codes de retour contre les déclarations globales d'en-tête afin de déterminer le type d'erreur survenue.


2 commentaires

J'ai oublié de mentionner que la méthode enregistrera déjà des informations (ID utilisateur ou un objet utilisateur) afin que je ne puisse pas retourner les codes d'erreur.


Parce qu'une fois que l'utilisateur a été créé, j'aimerais pouvoir suivre / utiliser des informations sur le nouvel utilisateur. Si la méthode renvoie un objet utilisateur, je peux continuer mon chemin. Si ce n'est pas le cas, je devrais alors exécuter une deuxième requête pour trouver l'utilisateur par son nom d'utilisateur. Bien que cela soit facile dans cette situation, car le nom d'utilisateur sera unique, il existe de nombreux exemples où j'aurais besoin de l'ID pour identifier les informations, par exemple. stocker des journaux.



0
votes

Cela devrait être fait de manière suivante -

Créer un objet d'erreur avec les codes d'erreur, texte d'erreur et la méthode qui a jeté l'erreur.

transmettez l'objet d'erreur.

Vous pouvez lancer des exceptions, mais des exceptions sont chères

Modifier - basé sur la modification de l'opération. Dans ce cas, vous devriez vous lancer un objet d'exception.

Créer une classe d'exception avec code d'erreur, description d'erreur, nom de classe, nom de la méthode. Jeter l'exception en arrière.


0 commentaires

-2
votes

Vous devez vérifier si le nom d'utilisateur existe avant d'appeler la méthode CreateUser (). Si vous ne le faites pas, ou quelque chose se passe entre le moment où vous avez vérifié et appelé CreateUser (), vous lancez une exception. Il n'est nulle part aussi près que cher tel qu'il est fait pour être.

Cela a-t-il un coût? Oui. Est-ce assez grand pour la matière? Plus probablement non.


8 commentaires

Il ne s'agit pas des dépenses, il s'agit d'un "utilisateur avec ce nom déjà existant" n'est pas vraiment une condition exceptionnelle. Il est effectivement prévu que cela se produirait. Jeter une exception est une abus de manipulation des exceptions.


C'est un non-sens sémantique! Avec ce type de raisonnement, vous pouvez expliquer toute erreur comme «attendu»


Si vous pouvez anticiper que cela peut arriver, alors vous vérifiez ce cas, avant d'essayer de créer l'utilisateur, avec ISUSERNAMETACKAKEKENK () ou quelque chose.


Non non Non Non Non. Ne pas "jeter une exception". Les exceptions sont conçues pour des circonstances exceptionnelles (d'où le nom). Vous pouvez facilement vérifier si un nom existe déjà et gère le cas de manière appropriée. Ce n'est pas un cas de bord spécial - c'est quelque chose qui pourrait être assez courant.


Vous êtes censé vérifier si le nom d'utilisateur existe avant d'appeler la méthode CreateSer (). Si vous ne le faites pas, ou quelque chose se passe entre le moment où vous avez vérifié et appelé CreateUser (), vous lancez une exception.


@Jason Je suis d'accord avec votre point de vue sur la sémantique des exceptions, mais que vous disiez que vous pouvez facilement vérifier n'est pas vrai. Eh bien, la vérification de celle-ci est triviale, mais le code restant pour passer ensuite l'erreur n'est pas. Sur tous les commentaires, personne n'a mis en avant une solution qui est vraiment élégante.


Vous ne faites pas d'erreur en vérification dans CreateUser (). Vous vous attendez à ce que le code client, vérifiez la disponibilité avec isusernamevalid (), avant d'appeler CreateUser (). Si CreateUser () échoue à cause de quelque chose comme une contrainte unique sur la table, vous jetez une sqlexception, et laissez un code de haut niveau plus haut. La vérification des erreurs dans CreateUser () est mauvaise, car vous ne pouvez pas vérifier si un nom d'utilisateur est pris, car il créerait l'utilisateur avec le nom donné dans le même Go.


@WISHCOW: Pourquoi devrais-je attraper une sqlexception avec un code UP plus élevé lorsque je peux gérer le problème plus bas, où il est plus facile de le gérer et de fournir à l'utilisateur une erreur informative. En outre, quelque chose peut arriver entre le temps isusternamevalid () est appelé et CreateUser () est appelé. Pour cette raison, il est sage de le laisser jusqu'à la dernière raison possible de vérifier les noms dupliqués. Enfin, je, ou un autre développeur, peut oublier de vérifier ISUSERNAMEVALID () lors de l'écriture du code. Lancer une exception qui n'est pas capturée m'interrogera rapidement de cette erreur, votre méthode passera non détectée.



1
votes

Je gère souvent ce genre de chose en collant ma validation dans un objet de domaine (comme un utilisateur).

Par exemple: P>

<?PHP
$auth = new AuthService();
$u = new User();
$u->username='Joe';
$u->password='secret';

$authResult = $auth->authenticate($user);

if ($authResult->success){
  //$user has properties set as a side effect.
}else{
  //find out why it failed.
  $errors = $authResult->getErrors();
}


0 commentaires

0
votes

Si vous contrôlez le type de retour de la méthode, vous pouvez également modifier sa signature pour renvoyer quelque chose comme un objet OperationResult qui aurait une propriété errordescription et une propriété ID utilisateur ou d'objet utilisateur.


1 commentaires

Renvoyer plusieurs éléments, un peu indépendants, des éléments d'une fonction ressemble à une odeur de code.



0
votes

moyen le plus simple: renvoyez NULL si la validation est passée et le message d'erreur s'il est échoué. Empêche la nécessité de faire des classes d'erreur ou des exceptions. Aussi le meilleur pour la performance.

EG. P>

$Form = new AjaxForm();
$Form->add(new TextBox('Username', 'usernameavailable|length[3,12]'));
$Form->add(new SubmitButton());


0 commentaires