Bu SO sorusunu okumak , kullanıcı girişini doğrulamak için istisnalar atmanın hoşnut olmadığı anlaşılıyor.
Ancak bu verileri kim doğrulamalı? Uygulamalarımda, tüm doğrulamalar iş katmanında yapılır, çünkü yalnızca sınıfın kendisi, özelliklerinin her biri için hangi değerlerin geçerli olduğunu gerçekten bilir. Bir özelliği doğrulamak için kuralları denetleyiciye kopyalayacak olsaydım, doğrulama kurallarının değişmesi mümkündür ve şimdi değişikliğin yapılması gereken iki yer vardır.
Doğrulamanın iş katmanı üzerinde yapılması gerektiği konusunda benim fikrim yanlış mı?
Ne yaptığım
Yani benim kod genellikle böyle biter:
<?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
}
Denetleyicide, giriş verilerini modele geçiririm ve kullanıcıya hata (lar) ı göstermek için atılan istisnaları yakalarım:
<?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);
}
Bu kötü bir metodoloji mi?
Alternatif yöntem
Belki de isValidAge($a)
doğru / yanlış döndürme için yöntemler oluşturmalı ve onları denetleyiciden çağırmalı mıyım?
<?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
}
Ve kontrolör temelde aynı olacak, sadece dene / yakala yerine şimdi / else varsa:
<?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);
}
Peki ne yapmalıyım?
Orijinal yöntemimle oldukça mutluyum ve genel olarak gösterdiğim meslektaşlarım bunu beğendi. Buna rağmen, alternatif yönteme geçmeli miyim? Yoksa bunu çok mu yanlış yapıyorum ve başka bir yol aramalıyım?
IValidateResults
.
ValidationException
ve diğer istisnalar değiştirdim