Лучший подход к проверке модели в 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
}
Author: Jonathan, 2013-03-04

1 answers

Я не думаю, что есть только один лучший подход, это зависит от того, как вы собираетесь использовать свои классы. В этом случае, когда у вас есть только простой объект данных, я бы предпочел использовать Подход № 2: Проверка с использованием методов проверки в классе модели.

Плохие вещи, на мой взгляд, не так уж и плохи:

Модель может находиться в недопустимом состоянии

Иногда желательно иметь модель в недопустимом состоянии.

Например, если вы заполните объект Person из веб-формы и хотите зарегистрировать его. Если вы используете первый подход, вам придется расширить класс Person, переопределить все установщики, чтобы перехватывать исключения, и тогда вы сможете перевести этот объект в недопустимое состояние для ведения журнала.

Разработчик должен помнить о вызове метода проверки is_valid()

Если модель абсолютно не должна находиться в недопустимом состоянии или метод требует, чтобы модель находилась в допустимом состоянии, вы всегда можете вызвать is_valid() изнутри класс, чтобы убедиться, что он находится в допустимом состоянии.

Класс модели может быть длинным из-за большого количества проверок

Код проверки все равно должен куда-то идти. Большинство редакторов позволяют вам сворачивать функции, так что это не должно быть проблемой при чтении кода. Во всяком случае, я думаю, что приятно иметь все подтверждения в одном месте.

 2
Author: mak, 2013-03-04 21:02:23