Behandlung von Fehlern in PHP bei Verwendung von MVC

12

Ich habe Codeigniter in letzter Zeit häufig verwendet, aber eine Sache, die mich nervt, ist, Fehler zu behandeln und sie dem Benutzer anzuzeigen. Ich war noch nie gut darin, mit Fehlern umzugehen, ohne dass es chaotisch wird. Mein Hauptanliegen ist die Rückgabe von Fehlern an den Benutzer.

Ist es empfehlenswert, Ausnahmen zu verwenden und Ausnahmen auszulösen / abzufangen, anstatt 0 oder 1 von Funktionen zurückzugeben und dann if / else zu verwenden, um die Fehler zu behandeln? Auf diese Weise wird es einfacher, den Benutzer über das Problem zu informieren.

Ich neige dazu, Ausnahmen zu vermeiden. Mein Java-Tutor an der Universität sagte mir vor einigen Jahren, "Ausnahmen sollten nicht in Produktionscode verwendet werden, sondern eher zum Debuggen." Ich habe das Gefühl, er hat gelogen.

Aber ich habe zum Beispiel Code, der einen Benutzer zu einer Datenbank hinzufügt. Während des Vorgangs können mehrere Probleme auftreten, z. B. ein Datenbankproblem, ein doppelter Eintrag, ein Serverproblem usw. Wenn während der Registrierung ein Problem auftritt, muss der Benutzer darüber informiert werden.

Was ist der beste Weg, um mit Fehlern in PHP umzugehen, wenn man bedenkt, dass ich ein MVC-Framework verwende?

James Jeffery
quelle

Antworten:

14

Ist es empfehlenswert, Ausnahmen zu verwenden und Ausnahmen auszulösen / abzufangen, anstatt 0 oder 1 von Funktionen zurückzugeben und dann if / else zu verwenden, um die Fehler zu behandeln? Auf diese Weise wird es einfacher, den Benutzer über das Problem zu informieren.

Nein nein Nein!

Mischen Sie keine Ausnahmen und Fehler. Ausnahmen sind außergewöhnlich. Fehler gibt es nicht. Wenn Sie einen Benutzer auffordern, eine Menge eines Produkts einzugeben, und der Benutzer "Hallo" eingibt, liegt ein Fehler vor. Dies ist keine Ausnahme: Es ist nichts Außergewöhnliches, wenn eine ungültige Eingabe des Benutzers angezeigt wird. Warum können Sie Ausnahmen nicht in Ausnahmefällen verwenden, z. B. bei der Validierung von Eingaben? Andere erklärten es bereits und zeigten eine gültige Alternative für die Eingabevalidierung.

Dies bedeutet auch, dass sich der Benutzer nicht um Ihre Ausnahmen kümmert und das Anzeigen der Ausnahmen sowohl unfreundlich als auch gefährlich ist . Beispielsweise zeigt eine Ausnahme während der Ausführung einer SQL-Abfrage häufig die Abfrage selbst an. Sind Sie sicher, dass Sie ein Risiko eingehen möchten, um diese Botschaft allen zu zeigen?

Es kann mehr als ein Fehler auftreten, z. B. ein Datenbankproblem, ein doppelter Eintrag, ein Serverproblem usw. Wenn während der Registrierung ein Problem auftritt, muss der Benutzer darüber informiert werden.

Falsch. Als Benutzer muss ich Ihre Datenbankprobleme, doppelten Einträge usw. nicht kennen. Ihre Probleme interessieren mich wirklich nicht . Was ich wissen muss ist, dass ich einen Benutzernamen eingegeben habe, der bereits existiert. Wie bereits gesagt, muss eine falsche Eingabe von mir einen Fehler auslösen, keine Ausnahme.

Wie werden diese Fehler ausgegeben? Es kommt auf den Kontext an. Für einen bereits verwendeten Benutzernamen würde ich gerne eine kleine rote Fahne neben dem Benutzernamen sehen, bevor ich das Formular abschicke, die besagt, dass der Benutzername bereits verwendet wird. Ohne JavaScript muss dieselbe Flagge nach der Übermittlung angezeigt werden.

Ein Beispiel für einen AJAX-fähigen Fehler

Bei anderen Fehlern würden Sie eine vollständige Seite mit einem Fehler anzeigen oder eine andere Methode wählen, um den Benutzer darüber zu informieren, dass ein Fehler aufgetreten ist (z. B. eine Meldung, die angezeigt wird und dann oben auf der Seite ausgeblendet wird). Die Frage bezieht sich dann mehr auf die Benutzererfahrung als auf die Programmierung.

Aus Sicht der Programmierer werden Sie den Fehler je nach Art des Fehlers auf unterschiedliche Weise verbreiten. Wenn beispielsweise ein Benutzername bereits vergeben ist, gibt eine AJAX-Anfrage nach http://example.com/?ajax=1&user-exists=Johnein JSON-Objekt zurück, das Folgendes angibt:

  • Dass der Benutzer bereits existiert,
  • Die Fehlermeldung, die dem Benutzer angezeigt werden soll.

Der zweite Punkt ist wichtig: Sie möchten sicherstellen, dass beim Senden des Formulars mit deaktiviertem JavaScript und beim Eingeben eines doppelten Benutzernamens mit aktiviertem JavaScript dieselbe Meldung angezeigt wird. Sie möchten den Text der Fehlermeldung nicht im serverseitigen Quellcode und in JavaScript duplizieren!

Dies ist tatsächlich die Technik, die von Stack Exhange-Websites verwendet wird. Wenn ich zum Beispiel versuche, meine eigene Antwort zu verbessern, enthält die AJAX-Antwort den anzuzeigenden Fehler:

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

Sie können auch einen anderen Ansatz wählen und die Fehler auf der HTML-Seite voreinstellen, bevor das Formular ausgefüllt wird. Vorteile: Sie müssen die Fehlermeldung nicht in der AJAX-Antwort senden. Nachteile: Wie steht es mit der Barrierefreiheit? Wenn Sie versuchen, die Seite ohne CSS zu durchsuchen, werden alle möglichen Fehler angezeigt.

Arseni Mourzenko
quelle
Ich schätze die Antwort. Genau damit habe ich zu kämpfen. Haben Sie Ressourcen zum Melden von Fehlern, insbesondere im Hinblick auf die Benutzerfreundlichkeit?
James Jeffery
Nun, wie gesagt, es hängt wirklich vom Fehler ab, und die Meldung von Fehlern an den Benutzer ist stark mit der Benutzeroberfläche verknüpft. Ich habe auch zwei Hauptmethoden für die Meldung von Fehlern hervorgehoben: eine enge Integration (eine AJAX-fähige rote Markierung in der Nähe der Eingabe mit einem falschen Wert) und Ganzseitenfehler, die weitaus weniger benutzerfreundlich sind und für schwerwiegendere Fälle verwendet werden. Beantwortet dies nicht Ihre Frage?
Arseni Mourzenko
2
+1 für es ist mehr ein User Experience-Problem und kein technisches
Charles Sprayberry
2
Bullshit, MainMa. Nur Blödsinn. Fehlercodes sind also 80er und 90er. Ausnahmen sind eine viel sauberere Methode, um mit besonderen Umständen wie falschen Eingaben umzugehen (z. B. ValidationException). Sie müssen dem Benutzer nicht jede Ausnahme anzeigen. Ich habe bessere Antworten von dir gesehen.
Falcon
2
Und für den Fall, dass Sie es nicht wussten: Sie können steuern, welche Ausnahmen Sie dem Benutzer präsentieren möchten und welche nicht. Das ist also überhaupt kein Argument.
Falcon
13

Ist es empfehlenswert, Ausnahmen zu verwenden und Ausnahmen auszulösen / abzufangen, anstatt 0 oder 1 von Funktionen zurückzugeben und dann if / else zu verwenden, um die Fehler zu behandeln? Auf diese Weise wird es einfacher, den Benutzer über das Problem zu informieren.

Ja Ja Ja!

Wenn Sie sauberen Code haben möchten, sollten Sie fast ausschließlich Ausnahmen verwenden und keine Fehlercodes verwenden. Fehlercodes sind bedeutungslos. Sie sind fast immer an eine numerische Konstante gebunden, die nicht viele Informationen preisgibt. Dadurch kann Ihr Code unleserlich werden und es wird schwierig, Daten zusammen mit dem Fehler weiterzugeben.

Ausnahmen sind Klassen und können beliebige Informationen enthalten. Der Benutzer hat also eine falsche Eingabe wie 'abc' für ein Zahlenfeld eingegeben. Mit einem Fehlercode könnten Sie diese Informationen nicht ohne viel Blubbern an den Behandler des Fehlers weitergeben. Etwas, das Ausnahmen kostenlos zur Verfügung stellen. Mit Ausnahmen können Sie aussagekräftige Rückgabewerte in Funktionen und Methoden haben und trotzdem elegant versagen. Noch besser ist, dass Ausnahmen direkt an den Ort weitergegeben werden, an dem Sie sie bearbeiten möchten! Stellen Sie sich die Menge an Spaghetti-Code vor, die Sie benötigen, um einen Fehlercode mit aussagekräftigen Daten an einen Handler weiterzuleiten, der ein oder zwei Ebenen darüber liegt.

Ausnahmen drücken sich auch semantischer aus als Fehlercodes. Fehlercodes führen zu Spaghetti-Code, während die Ausnahmebehandlung zu sauberem Code führt.

Außerdem kann man leicht vergessen, die Statuscodes zu überprüfen. In Sprachen wie Java sind Sie gezwungen, Ausnahmen zu behandeln (etwas, das beispielsweise in C # fehlt).

Was ist der beste Weg, um mit Fehlern in PHP umzugehen, wenn man bedenkt, dass ich ein MVC-Framework verwende?

Verwenden Sie Ausnahmen und behandeln Sie sie in Ihren Controllern.

Falke
quelle
Ich stimme dir sehr zu !! Obwohl Ausnahmen in PHP nicht so erzwungen werden wie in anderen Sprachen, ist es gut zu wissen, dass viele Leute sie inkorporieren ...
David Conde
6
Ich bin damit einverstanden, dass Fehlercodes in den meisten Fällen ziemlich bedeutungslos sind. Es ist jedoch extrem schlimm, Ausnahmen wohl oder übel zu werfen! Ausnahmen sollten nur für außergewöhnliche Umstände reserviert werden. Ausnahmen verursachen einen unvorhersehbaren Programmfluss, können es schwierig machen, dem Code zu folgen (und ihn daher zu warten), und in PHP sind sie im Vergleich zu IF / THEN / ELSE mit erheblichen Leistungseinbußen verbunden. Ich tendiere dazu, Methoden zu bevorzugen, die bei Erfolg wahr und bei Misserfolg falsch sind und nur eine Ausnahme auslösen, wenn etwas ungeheuer falsch läuft.
GordonM
6

Betrachten Sie diese handliche kleine Klasse:

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;            
    }

}

Das ist eine gute Verwendung von Ausnahmen. Aus der FunkyFile'sPerspektive kann absolut nichts unternommen werden, um die Situation zu verbessern, wenn der Pfad ungültig ist oder file_get_contentsfehlschlägt. Eine wirklich außergewöhnliche Situation;)

Aber gibt es einen Wert für Ihren Benutzer zu wissen, dass Sie irgendwo in Ihrem Code auf einen falschen Dateipfad gestoßen sind? Beispielsweise:

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!"; 
        }                           
    }        
}

Abgesehen davon, dass Sie anderen mitteilen, dass Sie einen schlechten Tag haben, haben Sie folgende Möglichkeiten:

  1. Zurückfallen

    Haben Sie eine andere Möglichkeit, die Informationen zu erhalten? In meinem einfachen Beispiel oben scheint dies nicht wahrscheinlich zu sein, es sei jedoch ein Master / Slave-Datenbankschema in Betracht gezogen. Der Master hat möglicherweise nicht geantwortet, aber vielleicht ist der Slave noch da draußen (oder umgekehrt).

  2. Ist es die Schuld des Benutzers?

    Hat der Benutzer eine fehlerhafte Eingabe übermittelt? Nun, erzähl ihr davon. Sie können entweder eine Fehlermeldung anstoßen oder nett sein und dieser Fehlermeldung ein Formular beilegen, damit sie den richtigen Pfad eingeben kann.

  3. Ist es deine Schuld?

    Und unter Ihnen verstehe ich alles, was nicht der Benutzer ist. Das reicht von der Eingabe eines falschen Dateipfads bis hin zu Fehlern auf Ihrem Server. Genau genommen ist es Zeit für einen 503-HTTP-Fehler , da der Dienst nicht verfügbar ist. CI hat eine show_404()Funktion, die man einfach aufbauen kann show_503().

Ratschlag, sollten Sie Rogue-Ausnahmen berücksichtigen. CodeIgniter ist ein unordentlicher Code, und Sie wissen nie, wann eine Ausnahme auftritt. In ähnlicher Weise können Sie Ihre eigenen Ausnahmen vergessen, und die sicherste Option ist die Implementierung eines Catch-All-Exception-Handlers. In PHP können Sie das mit set_exception_handler machen :

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

set_exception_handler("FunkyExceptionHandler");

Und Sie können sich auch über set_error_handler um unerwünschte Fehler kümmern . Sie können entweder den gleichen Handler wie für Ausnahmen schreiben oder alternativ alle Fehler in konvertieren ErrorExceptionund von Ihrem Ausnahmehandler behandeln lassen:

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");
yannis
quelle
Das war wirklich informativ, Prost!
James