Лучший подход к проверке модели в PHP? [закрыто]
Я узнал, что часто существует множество способов решения одной проблемы программирования, каждый подход, как правило, имеет свои преимущества и отрицательные побочные эффекты.
То, что я пытаюсь определить сегодня, - это лучший способ проверки модели в PHP. Используя пример человека, я описал четыре различных подхода, которые я использовал в прошлом, каждый из которых включает классы и пример использования, а также то, что мне нравится и не нравится в каждом подходе.
Мой вопрос здесь таков это: Какой подход, по вашему мнению, является лучшим? Или у вас есть лучший подход?
Подход № 1: Проверка с использованием методов настройки в классе моделей
Хорошее
- Простой, только один класс
- Создавая исключения, класс никогда не может находиться в недопустимом состоянии (за исключением бизнес-логики, т.Е. Смерть наступает до рождения)
- Не нужно помнить о вызове каких-либо методов проверки
Плохое
- Может возвращать только 1 ошибка (через
Exception
) - Требует использования исключений и их обнаружения, даже если ошибки не являются очень исключительными
- Может действовать только на один параметр, так как другие параметры еще не могут быть установлены (невозможно сравнить
birth_date
иdeath_date
) - Класс модели может быть длинным из-за большого количества проверок
class Person
{
public $name;
public $birth_date;
public $death_date;
public function set_name($name)
{
if (!is_string($name))
{
throw new Exception('Not a string.');
}
$this->name = $name;
}
public function set_birth_date($birth_date)
{
if (!is_string($birth_date))
{
throw new Exception('Not a string.');
}
if (!preg_match('/(\d{4})-([01]\d)-([0-3]\d)/', $birth_date))
{
throw new Exception('Not a valid date.');
}
$this->birth_date = $birth_date;
}
public function set_death_date($death_date)
{
if (!is_string($death_date))
{
throw new Exception('Not a string.');
}
if (!preg_match('/(\d{4})-([01]\d)-([0-3]\d)/', $death_date))
{
throw new Exception('Not a valid date.');
}
$this->death_date = $death_date;
}
}
// Usage:
try
{
$person = new Person();
$person->set_name('John');
$person->set_birth_date('1930-01-01');
$person->set_death_date('2010-06-06');
}
catch (Exception $exception)
{
// Handle error with $exception
}
Подход №2: Проверка с использованием методов проверки в классе моделей
Хорошее
- Простой, только один класс
- Возможно для проверки (сравнения) нескольких параметров (поскольку проверка выполняется после установки всех параметров модели)
- Может возвращать несколько ошибок (с помощью метода
errors()
) - Свобода от исключений
- Оставляет методы получения и установки доступными для других задач
Плохое
- Модель может находиться в недопустимом состоянии
- Разработчик должен помнить о вызове метода проверки
is_valid()
- Класс модели может быть длинным из-за большого количества проверка
class Person
{
public $name;
public $birth_date;
public $death_date;
private $errors;
public function errors()
{
return $this->errors;
}
public function is_valid()
{
$this->validate_name();
$this->validate_birth_date();
$this->validate_death_date();
return count($this->errors) === 0;
}
private function validate_name()
{
if (!is_string($this->name))
{
$this->errors['name'] = 'Not a string.';
}
}
private function validate_birth_date()
{
if (!is_string($this->birth_date))
{
$this->errors['birth_date'] = 'Not a string.';
break;
}
if (!preg_match('/(\d{4})-([01]\d)-([0-3]\d)/', $this->birth_date))
{
$this->errors['birth_date'] = 'Not a valid date.';
}
}
private function validate_death_date()
{
if (!is_string($this->death_date))
{
$this->errors['death_date'] = 'Not a string.';
break;
}
if (!preg_match('/(\d{4})-([01]\d)-([0-3]\d)/', $this->death_date))
{
$this->errors['death_date'] = 'Not a valid date.';
break;
}
if ($this->death_date < $this->birth_date)
{
$this->errors['death_date'] = 'Death cannot occur before birth';
}
}
}
// Usage:
$person = new Person();
$person->name = 'John';
$person->birth_date = '1930-01-01';
$person->death_date = '2010-06-06';
if (!$person->is_valid())
{
// Handle errors with $person->errors()
}
Подход № 3: Проверка в отдельном классе проверки
Хорошее
- Очень простые модели (вся проверка выполняется в отдельном классе)
- Возможно проверить (сравнить) несколько параметров (поскольку проверка выполняется после установки всех параметров модели)
- Может возвращать несколько ошибок (с помощью метода
errors()
) - Свобода от исключений
- Оставляет методы получения и установки доступными для других задачи
Плохое
- Немного сложнее, так как для каждой модели требуется два класса
- Модель может находиться в недопустимом состоянии
- Разработчик должен помнить об использовании класса проверки
class Person
{
public $name;
public $birth_date;
public $death_date;
}
class Person_Validator
{
private $person;
private $errors = array();
public function __construct(Person $person)
{
$this->person = $person;
}
public function errors()
{
return $this->errors;
}
public function is_valid()
{
$this->validate_name();
$this->validate_birth_date();
$this->validate_death_date();
return count($this->errors) === 0;
}
private function validate_name()
{
if (!is_string($this->person->name))
{
$this->errors['name'] = 'Not a string.';
}
}
private function validate_birth_date()
{
if (!is_string($this->person->birth_date))
{
$this->errors['birth_date'] = 'Not a string.';
break;
}
if (!preg_match('/(\d{4})-([01]\d)-([0-3]\d)/', $this->person->birth_date))
{
$this->errors['birth_date'] = 'Not a valid date.';
}
}
private function validate_death_date()
{
if (!is_string($this->person->death_date))
{
$this->errors['death_date'] = 'Not a string.';
break;
}
if (!preg_match('/(\d{4})-([01]\d)-([0-3]\d)/', $this->person->death_date))
{
$this->errors['death_date'] = 'Not a valid date.';
break;
}
if ($this->person->death_date < $this->person->birth_date)
{
$this->errors['death_date'] = 'Death cannot occur before birth';
}
}
}
// Usage:
$person = new Person();
$person->name = 'John';
$person->birth_date = '1930-01-01';
$person->death_date = '2010-06-06';
$validator = new Person_Validator($person);
if (!$validator->is_valid())
{
// Handle errors with $validator->errors()
}
Подход № 4: Проверка в классе модели и классе проверки
Хорошее
- Создавая исключения, класс никогда не может находиться в недопустимом состоянии (за исключением бизнес-логики, т.Е. Смерть наступает раньше рождение)
- Возможно проверить (сравнить) несколько параметров (поскольку бизнес-проверка выполняется после установки всех параметров модели)
- Может возвращать несколько ошибок (с помощью метода
errors()
) - Проверка организована в две группы: тип (класс модели) и бизнес (класс проверки)
- Оставляет методы получения и установки доступными для других задач
Плохое
- Обработка ошибок сложнее, если возникают исключения (модель класс) и массив ошибок (класс проверки)
- Немного сложнее, так как для каждой модели требуется два класса
- Разработчик должен помнить об использовании класса проверки
class Person
{
public $name;
public $birth_date;
public $death_date;
private function validate_name()
{
if (!is_string($this->person->name))
{
$this->errors['name'] = 'Not a string.';
}
}
private function validate_birth_date()
{
if (!is_string($this->person->birth_date))
{
$this->errors['birth_date'] = 'Not a string.';
break;
}
if (!preg_match('/(\d{4})-([01]\d)-([0-3]\d)/', $this->person->birth_date))
{
$this->errors['birth_date'] = 'Not a valid date.';
}
}
private function validate_death_date()
{
if (!is_string($this->person->death_date))
{
$this->errors['death_date'] = 'Not a string.';
break;
}
if (!preg_match('/(\d{4})-([01]\d)-([0-3]\d)/', $this->person->death_date))
{
$this->errors['death_date'] = 'Not a valid date.';
}
}
}
class Person_Validator
{
private $person;
private $errors = array();
public function __construct(Person $person)
{
$this->person = $person;
}
public function errors()
{
return $this->errors;
}
public function is_valid()
{
$this->validate_death_date();
return count($this->errors) === 0;
}
private function validate_death_date()
{
if ($this->person->death_date < $this->person->birth_date)
{
$this->errors['death_date'] = 'Death cannot occur before birth';
}
}
}
// Usage:
try
{
$person = new Person();
$person->set_name('John');
$person->set_birth_date('1930-01-01');
$person->set_death_date('2010-06-06');
$validator = new Person_Validator($person);
if (!$validator->is_valid())
{
// Handle errors with $validator->errors()
}
}
catch (Exception $exception)
{
// Handle error with $exception
}
1 answers
Я не думаю, что есть только один лучший подход, это зависит от того, как вы собираетесь использовать свои классы. В этом случае, когда у вас есть только простой объект данных, я бы предпочел использовать Подход № 2: Проверка с использованием методов проверки в классе модели.
Плохие вещи, на мой взгляд, не так уж и плохи:
Модель может находиться в недопустимом состоянии
Иногда желательно иметь модель в недопустимом состоянии.
Например, если вы заполните объект Person из веб-формы и хотите зарегистрировать его. Если вы используете первый подход, вам придется расширить класс Person, переопределить все установщики, чтобы перехватывать исключения, и тогда вы сможете перевести этот объект в недопустимое состояние для ведения журнала.
Разработчик должен помнить о вызове метода проверки is_valid()
Если модель абсолютно не должна находиться в недопустимом состоянии или метод требует, чтобы модель находилась в допустимом состоянии, вы всегда можете вызвать is_valid()
изнутри класс, чтобы убедиться, что он находится в допустимом состоянии.
Класс модели может быть длинным из-за большого количества проверок
Код проверки все равно должен куда-то идти. Большинство редакторов позволяют вам сворачивать функции, так что это не должно быть проблемой при чтении кода. Во всяком случае, я думаю, что приятно иметь все подтверждения в одном месте.