Beim Lesen dieser SO-Frage scheint es verpönt zu sein, Ausnahmen für die Überprüfung von Benutzereingaben auszulösen.
Aber wer sollte diese Daten validieren? In meinen Anwendungen werden alle Überprüfungen in der Geschäftsschicht durchgeführt, da nur die Klasse selbst wirklich weiß, welche Werte für jede ihrer Eigenschaften gültig sind. Wenn ich die Regeln für die Validierung einer Eigenschaft in den Controller kopieren würde, könnten sich die Validierungsregeln ändern, und jetzt gibt es zwei Stellen, an denen die Änderung vorgenommen werden sollte.
Ist meine Prämisse, dass die Validierung auf der Business-Ebene durchgeführt werden sollte, falsch?
Was ich mache
Mein Code endet normalerweise so:
<?php
class Person
{
private $name;
private $age;
public function setName($n) {
$n = trim($n);
if (mb_strlen($n) == 0) {
throw new ValidationException("Name cannot be empty");
}
$this->name = $n;
}
public function setAge($a) {
if (!is_int($a)) {
if (!ctype_digit(trim($a))) {
throw new ValidationException("Age $a is not valid");
}
$a = (int)$a;
}
if ($a < 0 || $a > 150) {
throw new ValidationException("Age $a is out of bounds");
}
$this->age = $a;
}
// other getters, setters and methods
}
In der Steuerung übergebe ich einfach die Eingabedaten an das Modell und fange ausgelöste Ausnahmen ab, um dem Benutzer die Fehler anzuzeigen:
<?php
$person = new Person();
$errors = array();
// global try for all exceptions other than ValidationException
try {
// validation and process (if everything ok)
try {
$person->setAge($_POST['age']);
} catch (ValidationException $e) {
$errors['age'] = $e->getMessage();
}
try {
$person->setName($_POST['name']);
} catch (ValidationException $e) {
$errors['name'] = $e->getMessage();
}
...
} catch (Exception $e) {
// log the error, send 500 internal server error to the client
// and finish the request
}
if (count($errors) == 0) {
// process
} else {
showErrorsToUser($errors);
}
Ist das eine schlechte Methode?
Alternative Methode
Sollte ich vielleicht Methoden für isValidAge($a)
diese Rückgabe true / false erstellen und sie dann vom Controller aufrufen?
<?php
class Person
{
private $name;
private $age;
public function setName($n) {
$n = trim($n);
if ($this->isValidName($n)) {
$this->name = $n;
} else {
throw new Exception("Invalid name");
}
}
public function setAge($a) {
if ($this->isValidAge($a)) {
$this->age = $a;
} else {
throw new Exception("Invalid age");
}
}
public function isValidName($n) {
$n = trim($n);
if (mb_strlen($n) == 0) {
return false;
}
return true;
}
public function isValidAge($a) {
if (!is_int($a)) {
if (!ctype_digit(trim($a))) {
return false;
}
$a = (int)$a;
}
if ($a < 0 || $a > 150) {
return false;
}
return true;
}
// other getters, setters and methods
}
Und der Controller wird im Grunde der gleiche sein, nur anstatt zu versuchen / fangen gibt es jetzt if / else:
<?php
$person = new Person();
$errors = array();
if ($person->isValidAge($age)) {
$person->setAge($age);
} catch (Exception $e) {
$errors['age'] = "Invalid age";
}
if ($person->isValidName($name)) {
$person->setName($name);
} catch (Exception $e) {
$errors['name'] = "Invalid name";
}
...
if (count($errors) == 0) {
// process
} else {
showErrorsToUser($errors);
}
Also was soll ich tun?
Ich bin ziemlich zufrieden mit meiner ursprünglichen Methode, und meine Kollegen, denen ich sie im Allgemeinen gezeigt habe, haben sie gemocht. Sollte ich trotzdem auf die alternative Methode umsteigen? Oder mache ich das furchtbar falsch und sollte nach einem anderen Weg suchen?
IValidateResults
.
ValidationException