web-dev-qa-db-fra.com

Erreurs de manutention dans PHP lorsque vous utilisez MVC

J'utilise beaucoup de codeignier récemment, mais une chose qui s'énerve sur mes nerfs est de manipuler des erreurs et de les afficher à l'utilisateur. Je n'ai jamais été bon pour manipuler des erreurs sans qu'il ne soit en désordre. Ma principale préoccupation est lorsque vous renvoyez des erreurs à l'utilisateur.

Est-il une bonne pratique d'utiliser des exceptions et de lancer/attraper des exceptions plutôt que de revenir 0 ou 1 des fonctions, puis d'utiliser si/else pour gérer les erreurs. Ainsi, il est donc plus facile d'informer l'utilisateur sur le problème.

J'ai tendance à disparaître des exceptions. My Java Tutor à l'université il y a quelques années m'a dit que "les exceptions ne devraient pas être utilisées dans le code de la production, c'est plus pour le débogage". Je reçois le sentiment qu'il a couché.

Mais, un exemple, j'ai un code qui ajoute un utilisateur à une base de données. Au cours du processus, plus d'une chose peut aller mal, telle qu'un problème de base de données, une entrée en double, une émission de serveur, etc. Lorsqu'un problème se produit lors de l'enregistrement dont l'utilisateur doit le savoir.

Quelle est la meilleure façon de gérer les erreurs dans PHP, en gardant à l'esprit que j'utilise un cadre MVC.

12
James Jeffery

Est-il une bonne pratique d'utiliser des exceptions et de lancer/attraper des exceptions plutôt que de revenir 0 ou 1 des fonctions, puis d'utiliser si/else pour gérer les erreurs. Ainsi, il est donc plus facile d'informer l'utilisateur sur le problème.

Non non Non!

Ne mélangez pas d'exceptions et d'erreurs. Les exceptions sont, bien, exceptionnelles. Les erreurs ne sont pas. Lorsque vous demandez à un utilisateur de saisir une quantité d'un produit et que l'utilisateur entre "Hello", c'est une erreur. Ce n'est pas une exception: il n'y a rien d'exceptionnel pour voir une entrée non valide de l'utilisateur. Pourquoi ne pouvez-vous pas utiliser des exceptions dans des cas non exceptionnels, comme lors de la validation de l'entrée? Autres personnes l'a déjà expliqué, et montrant une alternative valide pour la validation d'entrée.

Cela signifie également que l'utilisateur ne se soucie pas de votre exceptions, et montrant que les exceptions sont à la fois hostiles et dangereuses . Par exemple, une exception lors d'une exécution d'une requête SQL révèle souvent la requête elle-même. Êtes-vous sûr de vouloir prendre des risques pour montrer un tel message à tout le monde?

plus d'une chose pourrait se tromper, telle qu'un problème de base de données, une entrée en double, une émission de serveur, etc. Lorsqu'un problème se produit lors de l'enregistrement, l'utilisateur doit le savoir.

Tort. En tant qu'utilisateur, je n'ai pas besoin de connaître vos problèmes de base de données, des entrées en double, etc. Je ne me soucie vraiment pas de votre Problèmes. Qu'est-ce que je do besoin de savoir, c'est que je suis entré dans un nom d'utilisateur qui existe déjà. Comme déjà dit, une mauvaise entrée de moi doit déclencher une erreur, pas une exception.

Comment générer ces erreurs? Cela dépend du contexte. Pour un nom d'utilisateur déjà utilisé, j'aimerais voir un petit drapeau rouge apparaissant près du nom d'utilisateur, avant même de soumettre le formulaire, en disant que le nom d'utilisateur est déjà utilisé. Sans JavaScript, le même drapeau doit apparaître après la soumission.

An example of an AJAX-enabled error

Pour d'autres erreurs, vous montreriez une page complète avec une erreur ou choisissez une autre façon d'informer l'utilisateur que quelque chose s'est mal passé (par exemple un message qui apparaîtra, puis disparaissez en haut de la page). La question est ensuite liée davantage à expérience utilisateur qu'à la programmation.

Du point de vue des programmeurs, en fonction du type de l'erreur, vous le propagerez de différentes manières. Par exemple, dans un cas d'un nom d'utilisateur déjà pris, un AJAX Demande à http://example.com/?ajax=1&user-exists=John retournera un objet JSON indiquant:

  • Que l'utilisateur existe déjà,
  • Le message d'erreur à afficher à l'utilisateur.

Le deuxième point est important: vous voulez être sûr que le même message apparaisse à la fois lors de la soumission du formulaire avec JavaScript désactivé et de taper un nom d'utilisateur en double avec JavaScript activé. Vous ne voulez pas dupliquer le texte du message d'erreur dans le code source côté serveur et en JavaScript!

C'est en fait la technique utilisée par Stack Exhange Sites Web. Par exemple, si j'essaie de uppoter ma propre réponse, le AJAX Response contient l'erreur à afficher:

{"Success":false,"Warning":false,"NewScore":0,"Message":"You can't vote for your own post.",
"Refresh":false}

Vous pouvez également choisir une autre approche et prérégler les erreurs de la page HTML avant que le formulaire soit rempli. Avantages: Vous n'êtes pas obligé d'envoyer le message d'erreur dans AJAX Réponse. Inconvénients: Qu'en est-il de l'accessibilité? Essayez de parcourir la page sans CSS, et vous verrez toutes les erreurs éventuelles apparaissent.

14
Arseni Mourzenko

Est-il une bonne pratique d'utiliser des exceptions et de lancer/attraper des exceptions plutôt que de revenir 0 ou 1 des fonctions, puis d'utiliser si/else pour gérer les erreurs. Ainsi, il est donc plus facile d'informer l'utilisateur sur le problème.

Oui oui oui!

Si vous souhaitez avoir un code de nettoyage, vous devez utiliser presque exclusivement des exceptions et ne vous soucez pas d'utiliser des codes d'erreur. Les codes d'erreur n'ont pas de sens. Ils sont presque toujours liés à une constante numérique qui ne révèle pas beaucoup d'informations. Il peut rendre votre code illisible et il est difficile de propager des données à côté de l'erreur.

Les exceptions sont toutefois des cours et peuvent contenir toutes les informations que vous aimez. Donc, l'utilisateur a entré une mauvaise entrée, comme "ABC" pour un champ de numéro. Avec un code d'erreur, vous ne seriez pas en mesure de propager ces informations au gestionnaire de l'erreur sans beaucoup de bulles. Quelque chose que les exceptions prévoient gratuitement. De plus, des exceptions vous permettent d'avoir des valeurs de retour significatives dans des fonctions et des méthodes tout en ayant un moyen d'échouer avec élégance. Encore meilleures, des exceptions sont propagées directement à l'endroit où vous voulez les gérer! Imaginez la quantité de code spaghetti dont vous aurez besoin de propager un code d'erreur avec des données significatives à un gestionnaire une ou deux couches ci-dessus.

De plus, des exceptions expriment donc beaucoup plus sémantiquement que les codes d'erreur. Les codes d'erreur conduisent à un code spaghetti où la manipulation des exceptions conduit à un code de nettoyage.

De plus, il est facile d'oublier de vérifier les codes d'état. Dans des langues comme Java Vous êtes obligé de gérer des exceptions (quelque chose qui, par exemple, C # manque).

Quelle est la meilleure façon de gérer les erreurs dans PHP, en gardant à l'esprit que j'utilise un cadre MVC.

Utilisez des exceptions et gérez-les dans vos contrôleurs.

13
Falcon

Considérez cette petite classe pratique:

class FunkyFile {               

    private $path;
    private $contents = null;

    public function __construct($path) { 
        $this->setPath($path); 
    }

    private function setPath($path) {
        if( !is_file($path) || !is_readable($path) ) 
            throw new \InvalidArgumentException("Hm, that's not a valid file!");

        $this->path = realpath($path);
        return $this; 
    }

    public function getContents() {
        if( is_null($this->contents) ) {
            $this->contents = @file_get_contents( $this->path );
            if($this->contents === false) 
                throw new \Exception("Hm, I can't read the file, for some reason!");                                 
        }

        return $this->contents;            
    }

}

C'est une utilisation parfaitement fine d'exceptions. De FunkyFile's Perspective Il n'y a absolument rien qui puisse être fait pour remédier à la SITUATION si le chemin est invalide ou file_get_contents Échoue. Une situation vraiment exceptionnelle;)

Mais y a-t-il une valeur de votre utilisateur de savoir que vous avez trébuché sur un mauvais chemin de fichier, quelque part dans votre code? Par exemple:

class Welcome extends Controller {

    public function index() {

        /**
         * Ah, let's show user this file she asked for
         */                 
        try {
            $file = new File("HelloWorld.txt");
            $contents = $file->getContents();   
            echo $contents;
        } catch(\Exception $e) {
            log($e->getMessage());

            echo "Sorry, I'm having a bad day!"; 
        }                           
    }        
}

Autre que de dire aux gens que vous passez une mauvaise journée, vos options sont les suivantes:

  1. Rebackback

    Avez-vous une autre façon d'obtenir l'information? Dans mon exemple simple ci-dessus, cela ne semble pas probable, mais envisager un schéma de base de données maître/esclave. Le maître peut avoir échoué à réagir mais peut-être, juste peut-être que l'esclave est toujours là (ou vice versa).

  2. Est-ce la faute de l'utilisateur?

    L'utilisateur a-t-il soumis une entrée défectueuse? Eh bien, parlez-la de ça. Vous pouvez augmenter un message d'erreur ou être agréable et accompagner ce message d'erreur avec un formulaire afin qu'elle puisse saisir le chemin correct.

  3. Est-ce votre faute?

    Et par vous, je veux dire tout ce qui est pas L'utilisateur, de sorte que cela vous permet de saisir un mauvais chemin de fichier, à quelque chose qui va mal dans votre serveur. Strictement parlant, il est temps pour une 503 error HTTP , comme le service est indisponible. CI a une fonction show_404(), vous pouvez facilement construire show_503().

Bord de conseil, vous devriez prendre en considération des exceptions de voyous. Ledicdigniter est un code de code désordonné et vous ne savez jamais quand une exception apparaîtra. De même, vous pouvez oublier vos propres exceptions et l'option la plus sûre consiste à implémenter une prise de pratique de toutes les exceptions. IN PHP vous pouvez le faire avec Set_Exception_Handler :

function FunkyExceptionHandler($exception) {
    if(ENVIRONMENT == "production") {
        log($e->getMessage());
        show_503();
    } else {
        echo "Uncaught exception: " , $exception->getMessage(), "\n";
    }   
}

set_exception_handler("FunkyExceptionHandler");

Et vous pouvez également prendre en charge les erreurs de voyous, via Set_error_handler . Vous pouvez écrire le même gestionnaire que pour des exceptions ou convertir toutes les erreurs en ErrorException et que votre gestionnaire d'exception traite avec eux:

function FunkyErrorHandler($errno, $errstr, $errfile, $errline) {
    // will be caught by FunkyExceptionHandler if not handled
    throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}

set_error_handler("FunkyErrorHandler");
6
yannis