Объект домена: сеттеры и геттеры или просто общедоступные свойства?

Должен ли я проверять свойства объекта домена при их установке?

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

Должен ли я проверять свойства объекта домена именно так или вообще не должен их проверять?

В последнем случае я могу просто удалить все сеттеры и геттеры и просто сделать свойства объекта домена общедоступными, чтобы я мог просто взаимодействовать с ними напрямую.

class User
{
    private $id;
    private $firstname;
    private $lastname;
    private $email;
    private $password;
    private $registerDate;

    public function setId($id)
    {
        if (is_int($id)) {
            $this->id = $id;
        } else {
            throw new Exception('Parameter must be an integer.');
        }
    }

    public function setFirstname($firstname)
    {
        if (is_string($firstname)) {
            $this->firstname = $firstname;
        } else {
            throw new Exception('Parameter must be a string.');
        }
    }

    //{ etc setters }

    public function __get($property) {
        if (property_exists($this, $property)) {
            return $this->$property;
        }
    }
}

person Kid Diamond    schedule 12.06.2014    source источник
comment
Вам действительно нужно проверять переменную по типу?   -  person barell    schedule 12.06.2014


Ответы (2)


Проверка примитивных типов в динамическом, слабо типизированном языке кажется мне излишним в 99% случаев. На самом деле не имеет значения, является ли ваша $firstname правильной строкой или нет, она все равно будет неявно преобразована в одну, когда это необходимо.

Однако иногда имеет смысл проверить, соответствует ли значение примитива, переданного в качестве аргумента (не его тип, некоторым конкретным ограничениям бизнес-логики):

function squareRoot($number) {
    if(!is_numeric($number) || $number < 0)
        throw new \InvalidArgumentException("Positive number expected.");
    return sqrt($number);
}

Тем не менее, я бы использовал этот вид бюрократии только в случае крайней необходимости. Если кто-то хочет передать нечисловую строку методу с именем setNumber($number) с типом документа, указывающим, что $number является числом, это его проблема, если в результате произойдут плохие вещи.

С методами, ожидающими объект определенного типа (или реализующий определенный интерфейс) в качестве аргументов, вместо этого используйте подсказку типа:

function foo(BarObject $bar) {
    // ...
}

Это также работает с массивами:

function doStuffWithArray(array $a) {
    // ...
}

Интересно, что нет подсказки типа, которая позволяла бы и массивам, и объектам реализовывать интерфейс \ArrayAccess, но это лишь одна из многих особенностей PHP.

person lafor    schedule 12.06.2014

Мой совет — перенести логику проверки из сущностей в класс, который их сохраняет, будь то сопоставитель данных, репозиторий или что-то еще. Или, что лучше, отдельный класс валидатора для каждого типа сущности/агрегированного корня.

Почему? Разделение забот.

Давайте подумаем о проверке. Я вижу два типа валидаторов. Первый - проверка типа/диапазона, например, "Имя пользователя должно быть строкой и содержать от 5 до 50 символов". Второй - проверка домена, например, "Электронная почта должна быть уникальной". Проверка домена может быть дорогостоящей и обычно требует множества вспомогательных классов (службы, преобразователи данных, адаптеры базы данных и т. д.).

person Lauris    schedule 12.06.2014
comment
В этом случае мои объекты домена будут просто классами без сеттера и геттера. Они будут содержать только методы, возвращающие состояние (isLoggedIn() и т. д.), а свойства будут общедоступными, верно? - person Kid Diamond; 12.06.2014
comment
Это зависит от вас. Я бы оставил геттеры и сеттеры, потому что при изменении одного поля вам также может понадобиться изменить или вычислить другое. Например, setBirthday($birthday) { $this-›birthday = $birthday; $this-›horoscope = /* Вычислить знак гороскопа от $birthday */; } - person Lauris; 12.06.2014
comment
Ну, в моем гипсе они не имеют отношения друг к другу. - person Kid Diamond; 12.06.2014
comment
Тогда общедоступные свойства и необязательные методы сущностей, специфичные для предметной области, будут полностью в порядке. - person Lauris; 12.06.2014
comment
Еще одна вещь - isLoggedIn() принадлежит к какому-то классу AuthService, потому что здесь задействовано много вещей, таких как сеанс, доступ к базе данных, запрос файлов cookie,... - person Lauris; 12.06.2014