การอ่านคำถาม 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และข้อยกเว้นอื่น ๆ