このSOの質問を読むと、ユーザー入力を検証するために例外をスローすることは不快に思われるようです。
しかし、誰がこのデータを検証する必要がありますか?私のアプリケーションでは、すべての検証はビジネスレイヤーで行われます。これは、クラス自体だけが、各プロパティの有効な値を実際に認識しているためです。プロパティを検証するためのルールをコントローラーにコピーすると、検証ルールが変更される可能性があり、変更を行う場所が2つあります。
ビジネス層で検証を行う必要があるという私の前提は間違っていますか?
私がやること
したがって、私のコードは通常、次のようになります。
<?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
}
コントローラーでは、入力データをモデルに渡し、スローされた例外をキャッチしてユーザーにエラーを表示します。
<?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);
}
これは悪い方法ですか?
別の方法
多分私はisValidAge($a)
true / falseを返すためのメソッドを作成してからコントローラからそれらを呼び出す必要がありますか?
<?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
}
そしてコントローラーは基本的に同じですが、try / catchの代わりに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);
}
それで、私は何をすべきですか?
私は元の方法にかなり満足しており、一般にそれを示した同僚はそれを気に入っていました。それにもかかわらず、別の方法に変更する必要がありますか?それとも私はこれをひどく間違っているので別の方法を探すべきですか?
IValidateResults
。
ValidationException
してその他の例外を修正しました