Constructor injection VS Setter Injection - флейм из плейсхолдеров

fixxxer

К.О.
Партнер клуба
И, конечно же, узконаправленная универсальная библиотека, не завязанная ни на какой фреймворк, подобная SafeMysql, не может навязывать использование DI.
 

Вурдалак

Продвинутый новичок
PHP:
$dep and $this->dep = $dep;
?!

В твоём втором примере та же проблема: если уж ты инъектишь через конструктор, то дефолтный инстанс нужно пихать в конструктор же, иначе у тебя $this->dep в непонятном состоянии и когда им можно пользоваться будет определяться по тому вызывался ли до этого $this->getDep(). Ну, и getter тогда уже и не нужен будет.
PHP:
class Foo {
    protected $dep=null;

    public function __construct(IDep $dep = null) {
        $this->dep = $dep ?: new DefaultDep;
    }
}
 
Последнее редактирование:
  • Like
Реакции: Gas

AmdY

Пью пиво
Команда форума
Вурдалак
у него ленивец, которого в любой момент можно менять, если ещё добавить и сеттер.

я старасюь говнокодить и интерфейс зависимости заменять передачей коллбэка с биндингом, чтобы юзать $this
PHP:
$class->setParser(function() {
    $query = $this->getQuery();
      ///
});
вообще, последнее время стараюсь писать говнокод вместо лазаньи, лябды здесь очень здорово помогают обеспечивать большую гибкость. при малых усилиях.
 

fixxxer

К.О.
Партнер клуба
Вурдалак
да те же яйца, вид сбоку. Мой вариант принципиально не отличается ничем, кроме того, что инстанс создается только когда он нужен. Не вижу предмета для спора
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
По определению конструктора.
8-( )
конструктор класса — специальный блок инструкций, вызываемый при создании объекта. задача — инициализировать члены объекта и определить инвариант класса
СПГС detected

Во всяком случае, в моём понимании, конструктор должен создавать валидный объект: http://martinfowler.com/articles/injection.html#ConstructorVersusSetterInjection. Это подход правильнее, но не всегда удобнее. А уж в приведённом примере, очевидно, никаких неудобств нет.
А статьи надо читать полностью:
Constructors with parameters give you a clear statement of what it means to create a valid object in an obvious place. If there's more than one way to do it, create multiple constructors that show the different combinations.
но в PHP перегрузка методов невозможна и многовариантная инициализация через конструктор неудобна в отличие от языка, на котором пишет Фаулер

То есть я не против того или иного. Если объект опциональный, то лучше как раз через setter.
а всего несколько часов час назад было
Через конструктор по-любому лучше.
правильнее через конструктор
:)

Ты ж к чему-то тут приплёл «tell, don't ask». А к чему — так и не объяснил. А ведь так хотелось послушать учителя.
прости, но я не учитель, я могу объяснить почему я считаю, что здесь setter лучше и при чем тут tell don't ask, но я не претендую на то, чтобы учить кого-то
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
инициализация через конструктор мне кажется неудобной вот почему:

в отдельные классы можно вынести 4 объекта, которые при желании можно подменить, это SafeDbParser - наш парсер параметров, SafeDbParameters - класс приведения данных к типам, SafeDbQuery - подготовка запроса для конкретной базы, и обертка для результата запроса.

Передавать в конструктор все 4 объекта сразу никому не нужно, а писать
__construct(null,null, null,$queryResultWrapper) - нечитабельно
варианты решения, которые я вижу: а) сеттеры б) массив параметров в конструктор
массив параметров не позволяет закрепить типизацию, и для публичной библиотеки не подходит

а как ты это видишь?
 
Последнее редактирование:

grigori

( ͡° ͜ʖ ͡°)
Команда форума
насчет tell don't ask:

Смена парсера нужна будет очень-очень редко, и вообще не факт что его надо отделять, но раз народ поднимает вопрос, можно сказать: "пиши свой парсер, флаг тебе в руки!". Т.е. я смотрю на парсер не как на внешний модуль, а как на код, поведение которого можно изменить.

я считаю параметр конструктора принципом ask, хотя это и некорректное использование термина :)
несмотря на то, что дефолтное значение решает эту проблему, мы все-равно явно спрашиваем какой парсер нам использовать, а в этом нет смысла
 
Последнее редактирование:

Вурдалак

Продвинутый новичок
А, так grigori понимает под «tell, don't ask» что-то своё, тогда ладно.
в отдельные классы можно вынести 4 объекта
Если 4, то можно сделать ValueObject, там и типизация будет. Но раз уж их 4, то проще setter'ами, да.
а всего несколько часов час назад было
Ну, Гриша, опять троллишь, ай-яй-яй. Парсер — обязательная зависимость, а не опциональная.
 
Последнее редактирование:

fixxxer

К.О.
Партнер клуба
не, ну ask это типа $foo->getTitle(), тут ты вкладываешь в tell dont' ask какой-то свой смысл

насчет конструктора, "псевдоперегрузка"-то делается легко, типа
PHP:
class Foo {
    static public function constructByBlahBlah(...) {
        $self = new static;
        $self->setBlah(...);
        return $self;
    }
}
Но это все фигня и не особо в тему.

На самом деле, мы говорим о библиотеке типа safeMysql или "вообще", о том, как делать в проекте?

В проекте важно выработать один подход и его придерживаться во всем проекте. Не важно, какой DI или там сервис-локатор, важно, чтобы везде был один стиль - иначе хрен поймешь, откуда что берется и как где что перебить.

Для внешних самостоятельных библиотек разумно предусмотреть все способы (конструктор + сеттер) - ведь их придется интегрировать в кучу разных фреймворков с самыми различными вариантами управления зависимостями. И, конечно, предусмотреть дефолты, для использования которых не надо делать ничего.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
А, так grigori понимает под tell, don't ask что-то своё, тогда ладно.
да, я некорректен, простите
Если 4, то можно сделать ValueObject, там и типизация будет. Но раз уж их 4, то проще setter'ами, да.
то есть
PHP:
$params = new SafeDbParams();
$params->setParser($MyParser);
new SafeDb($params);
:)
а "их" почему-то всегда много, и если сейчас параметр один - то через месяц почти всегда добавится еще, и здравствуй рефакторинг
Ну, Гриша, опять троллишь, ай-яй-яй. Парсер — обязательная зависимость, а не опциональная.
а что, только тебе можно? :)
парсер - больше, чем зависимость, это неотъемлемая часть с возможностью переопределения, которая в реальности никому не нужна
 

hell0w0rd

Продвинутый новичок
По моему через сеттеры можно устанавливать то, что можно менять. Если первоначальной задачей было не допустить вопроса о том, почему парсер работает так, а не иначе - то его, парсер, менять нельзя.
На мой взгляд можно не думать об апи конструктора, пусть оно будет убогое, но гибкое, но также сделать статик-метод, createDefault, который будет принимать параметры старого конструктора, а в новый подставлять стандартные параметры.
Вот пример такого поведения
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
>насчет конструктора, "псевдоперегрузка"-то делается легко, типа
а ведь да, new static решило много проблем

>На самом деле, мы говорим о библиотеке типа safeMysql или "вообще", о том, как делать в проекте?
я думаю, про либу, в приложениях немаловажные требование - скорость написания, баланс, единство стиля, а не красота

надо ли предусматривать параметры в конструкторе - видимо, раз есть такие любители, значит, надо

>через сеттеры можно устанавливать то, что можно менять.
через сеттер можно еще и обработывать перед тем, как менять - например, выкинуть exception если значение уже установлено
 

Redjik

Джедай-мастер
Сеттеры удобнее тем, что (по крайней мере в нашем случае) мы можем инжектить объекты на уровне конфига.
С конструктором тоже можно, но как то не красиво.
 

WMix

герр M:)ller
Партнер клуба
Redjik
мне кажется как раз наоборот, через конструктор легко слепить Di, что заранее установит парсер.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
WMix под нашим случаем имеется ввиду yii с инициализацией через установку публичных полей из конфига
 
Сверху