guten tag.
soll man exceptions auch zur user input validierung verwenden?
oder nur für fehlzustände im programm?
also zum beispiel
CheckUsername($name) {
if(strlen(name)>4)
throw new Exception("zu kurz")....
}
guten tag.
soll man exceptions auch zur user input validierung verwenden?
oder nur für fehlzustände im programm?
also zum beispiel
CheckUsername($name) {
if(strlen(name)>4)
throw new Exception("zu kurz")....
}
Kann man. Allerdings musst du da eher eine UsernameInvalidException werfen, nur Exception ist ziemlich ungenau und kann ich richtig abgefangen werden.
EDIT:
Als Beispiel hier ein Auszug aus einer Login-Methode die ich regelmäßig benutze:
class User
{
/** blabla **/
/**
* ... doku ...
* @throws MySqlQueryException, PermissionBlockedException, NotFoundException, PermissionDeniedException
* @return User
*/
public static function loginAs($username, $password) {
// Login-Blockzeit prüfen (zu viele falsche PWs...) //
if (true)
{ // der login is noch geblockt
throw new PermissionBlockedException();
}
// datensatz des users auslesen //
if (!$users_exists)
{ // den Users gibts nicht
throw new NotFoundException();
}
// passwort prüfen
if (!$pw_ok)
{ // falsches passwort
// counter für falsche logins setzen bzw. erhöhen
// bei erreichen des limits den login für die IP sperren
throw new PermissionDeniedException();
}
self::$currentUser = new User($row);
$_SESSION['user'] = self::$currentUser;
return self::$currentUser;
}
}
Alles anzeigen
Kann man. Allerdings musst du da eher eine UsernameInvalidException werfen, nur Exception ist ziemlich ungenau und kann ich richtig abgefangen werden.
Naja, außer in wirklich großen Projekten an denen mehrere Leute arbeiten und die umfangreich konzeptioniert und dokumentiert werden, schmeiße ich auch immer nur normale Exceptions. Die Genauigkeit erhalte ich über die Message die geschmissen wird, da kann ich sogar noch viel präziser werden als einfach nur durch den Klassennamen der Exception.
Wo das Problem beim abfangen sein soll kann ich auch nicht wirklich erkennen.
Das Problem ist folgendes:
function registerUser($name, array $data)
{
// username zu kurz
throw Exception();
// username zu lang
throw Exception();
// username enthält zu kurzes Zeichen
throw Exception();
// username gibts bereits
throw Exception();
// datenbank mag nicht
throw Exception();
// bestätigungs-mail konnte nich gesendet werden
throw Exception();
}
Alles anzeigen
Egal welcher fehler aufritt, es fliegt immer nur Exception. D.h. du musst noch einen switch-case block einführen um die Verschiedenen Szenarien zu behandeln (andere Fehlermeldung ausgeben).
function registerUser($name, array $data)
{
// username zu kurz
throw UsernameInvalidException("too_short");
// username zu lang
throw UsernameInvalidException("too_long");
// username enthält zu kurzes Zeichen
throw UsernameInvalidException("unsupported_char");
// username gibts bereits
throw UsernameExistsException();
// datenbank mag nicht
throw MySqlException();
// bestätigungs-mail konnte nich gesendet werden
throw IOException("email_fail");
}
Alles anzeigen
Jetzt kannst du z.B. im fall einer UsernameInvalidException immer die gleiche Fehlermeldung ausgeben (z.B. "Username ungültig") und/oder die Message in Verbindung mit einer Sprachdatei nutzen und dynamisch die passende Meldung erstellen.
Bei allen anderen Exceptions der Funktion (UsernameExistsException, MySqlException, IOException) weisst du stehts schon zum Zeitpunkt des Programmierens, was genau falsch gelaufen ist und nicht erst zur runtime. Dazu kommt, dass der Code übersichtlicher (und für aussenstehende einfacher zu lesen) wird, sowie das Programm merkbar schneller, wenn es sich um Boilerplate-Code handelt.
function registerUser($name, array $data)
{
// username zu kurz
throw Exception("username zu kurz");
// username zu lang
throw Exception("username zu lang");
// username enthält zu kurzes Zeichen
throw Exception("username enthält zu kurzes Zeichen");
// username gibts bereits
throw Exception("username gibts bereits");
// datenbank mag nicht
throw Exception("datenbank mag nicht");
// bestätigungs-mail konnte nich gesendet werden
throw Exception("bestätigungs-mail konnte nich gesendet werden");
}
try {
registerUser($name,$data);
echo "User wurde erfolgreich registriert.";
}
catch(Exception $e) {
echo $e->getMessage();
}
Alles anzeigen
Was ist mit Mehrsprachigkeit? Was ist mit spezieller Fehlerbehandlung? Wenn z.B. der user schon in der Datenbank steht, die E-Mail aber nicht raus ging (höchstwahrscheinlich, weil die Adresse flasch ist) musst du ihn wieder löschen, damit er sich mit einer korrekten E-Mail wieder registrieren kann.
Also ich bitte dich Tobse...
Das war selbstverständlich nur ein simplifiziertes Beispiel. Selbstverständlich werden die Fehlermeldungen in der Praxis mittels Platzhaltern, Variablen oder Konstanten gesetzt.
Genauso kann man zusätzlich Errorcodes angeben. Und ob man jetzt zig verschiedene Catch-Blöcke schreiben muss um die verschiedenen Exceptions abzufangen, oder ob man ein switch-Anweisung für die Errorcodes schreibt, ist nun wirklich kein nennenswerter Unterschied. Ich habe ein komplettes Framework und ein ORM selber geschrieben und schon mehr Projekte umgesetzt als ich noch zählen kann. Früher meinte ich auch es wär toll für jeden Blödsinn eine eigene Exception zu definieren. Die Erfahrung hat mich gelehrt, dass es überflüssig ist, ich habe es noch nicht ein einziges Mal benötigt.
Wenn du persönlich es toller findest unzählige verschiedene Exceptions zu definieren dann tu das, aber behaupte bitte nicht das wäre nötig.
Das es nötig ist, habe ich nicht behauptet. Du kannst auch für jede Methode eine Zuweisung von Rückgabewert zu Fehler / korrekter Ausführung definieren (so wie es in PHP leider mit z.B. strpos noch so is). Dass das aber nicht gerade Best-Practice ist, werde ich dir nicht sagen müssen.
Ich, im Gegensatz zu dir, habe in Projekten mit mehreren Programmierern die Erfahrung gemacht, dass des einen unnötigen Auwand darstellt, sich durch die einzelnen Messages für Exception für jede Methode durchzuarbeiten anstatt einen Satz von 20 Excpetions auswendig zu kennen, der überall Anwendung findet. Soll sich der TE aussuchen, was besser ist.
Das mal beiseite, verwendet ihr wirklich Exceptions für Validierungsfehler? Das gehört für mich zum normalen Programmablauf, Exceptions verwende ich nur für Ereignisse, die eigentlich nicht auftreten sollten, z.B. HTTP-Exceptions (404, 500 etc.), Datenbankfehler und ähnliches.
Allerdings nehme ich die Validierung mittlerweile sowieso meist auf dem Client vor, Serverseitig löse ich dann auch eine ValidationException aus welche ein Array von Fehlern zurück gibt. Allerdings tritt diese Exception ja dank der Client-seitigen Validierung nur dann auf, wenn die Daten mutwillig verändert wurden, damit handelt es sich eben wieder um eine Ausnahme ausserhalb des normalen Programmablaufs und verdient damit eine Exception.
Ich, im Gegensatz zu dir, habe in Projekten mit mehreren Programmierern die Erfahrung gemacht, dass des einen unnötigen Auwand darstellt, sich durch die einzelnen Messages für Exception für jede Methode durchzuarbeiten anstatt einen Satz von 20 Excpetions auswendig zu kennen, der überall Anwendung findet. Soll sich der TE aussuchen, was besser ist.
Und was vermutest du, wieviele der Leute die so etwas in einem Forum fragen in Teams an wirklich großen Projekten arbeiten? Ich bin grundsätzlich auch immer für klare Strukturen, Abstraktionen, Aufteilungen von Aufgabenbereichen und entsprechende Kapselung. Wie gesagt habe ich es für Exceptions aufgegeben weil mir noch nicht ein Fall untergekommen ist, wo es mir einen echten Mehrwert geboten hätte.
Das Beispiel "User wird in die Datenbank eingetragen aber dann kann die E-Mail nicht gesendet werden" ist für mich obsolet, da Validierung, Speicherung in der DB und Versand von E-Mails für mich drei verschiedene Aufgaben sind die nicht in einer Methode abgearbeitet werden. Unter anderem auch aus diesem Grund der klaren Trennung von Aufgabenbereichen machen für mich verschiedene Exceptions nicht sonderlich Sinn. Die Art der Exception wird so schon durch die Stelle an der sie auftritt definiert, da brauch ich keine eigene Klasse für definieren.
Aber wie du schon sagst, der TE soll selber schauen wie es für ihn am meisten Sinn ergibt. Ich fand nur deine Formulierung im ersten Post zu strikt.
lukasn:
Exceptions schmeiße ich dann, wenn eine Funktion/Methode die Aufgabe für die sie gedacht ist nicht ausführen kann. Eine Funktion registerUser() soll einen User registrieren. Kann sie diese Aufgabe nicht ausführen wird eine Exception geschmissen. Anders sähe es beispielsweise bei einer Funktion isValid() aus, da gehört es zur Aufgabe der Funktion Daten zu validieren, und eine fehlgeschlagene Validation ist in dem Fall keine Exception.