การอ่านคำถาม 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
}
ในคอนโทรลเลอร์ฉันเพิ่งส่งข้อมูลอินพุตไปยังโมเดลและดักจับข้อยกเว้นเพื่อแสดงข้อผิดพลาดไปยังผู้ใช้:
<?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)
ส่งคืนจริง / เท็จแล้วเรียกพวกเขาจากตัวควบคุม?
<?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
}
และคอนโทรลเลอร์จะเหมือนกันโดยทั่วไปแทนที่จะลอง / จับตอนนี้ถ้า / อื่น ๆ :
<?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
และข้อยกเว้นอื่น ๆ