Dependency injection и envy зависимости.

Yoskaldyr

"Спамер"
Партнер клуба
Если посмотреть на Symfony и Zend, то они, по моему, используют http://php-di.org/ , но возможно с обертками.
не нашел смайла facepalm...

Я вас как-то не понимаю. Если что-то для чего-то нужно, то это мы создаем.
Если не нужно то нет.
Или вы с этим не согласны?
проблема в другом - если на 2-м уровне вложенности просто вылетела ошибка и дальше не пойдет (тупо валидация или что-то подобное), то классы нижнего уровня просто не понадобятся (в большинстве случаев это пофиг, но иногда конструкторы бывают реально тяжелые). Есть подозрение как раз поэтому на DI все тупо забивают болт (но это не точно :) )

P.S. код в студию! не ну реально без кода получается что все что существует это треш. feature envy - это стандарт де факто, сервис локатор - тоже стандарт.
 

Yoskaldyr

"Спамер"
Партнер клуба
Вопрос ведь реально простой. Почему хороший код даже на сях есть (учитывая более неоднозначные моменты языка по сравнению с пхп), а на более структурированном и простом языке нормального и красивого кода который решает какую-то практическую задачу нет?
 

флоппик

promotor fidei
Команда форума
Партнер клуба
проблема в другом - если на 2-м уровне вложенности просто вылетела ошибка и дальше не пойдет (тупо валидация или что-то подобное), то классы нижнего уровня просто не понадобятся (в большинстве случаев это пофиг, но иногда конструкторы бывают реально тяжелые). Есть подозрение как раз поэтому на DI все тупо забивают болт (но это не точно :) )
Если у тебя конструкторы тяжелые - это уже проблема безо всякого DI.
 

WMix

герр M:)ller
Партнер клуба
@Yoskaldyr по простому
PHP:
class Di{

    private $conf;
  
    public function __construct( $conf ){
        $this->conf = $conf;
    }

    public function get( string $key ){
        if( isset($this->conf[$key]) ){
            if(is_callable($this->conf[$key])){
                return ($this->conf[$key])($this);
            }
            return $this->conf[$key];
        }
        throw new \InvalidArgumentException('can\'t resolve '.$key);
    }
}

// допустим есть зависимость А
class A{}

// в классе В
class B{
    private $a;
    public function  __construct(A $a){
        $this->a = $a;
    }
}
// описали
$di = new Di([
    'A' => function($di){
        return new A;
    },
    'B' => function($di){
        return new B($di->get('A'));
    }
]);

// получили
print_r($di->get('B'));
 

Yoskaldyr

"Спамер"
Партнер клуба
@WMix Я же не спорю с реализацией :) И не спрашиваю как делать. Вариантов много, на любой вкус и цвет - от простейших как у тебя до различных наворотов. В примере только 1 уровень вложенности и 1 параметр у конструкторов. Чем больше уровней и параметров (даже совсем немного 2-3), то количество классов расчет очень быстро - получить инициализацию 30 классов очень легко, а использоваться будут классы только первого уровня (например, не прошла валидация и т.п.).

Я говорю о реальных проектах. Взять тот же друпал - большой, представители друпала в php-fig, на симфони компонентах, версия на симфони была написана с нуля, т.е. не должно юыть никакого легаси. А в результате нет там полноценного DI, только обычный сервис локатор, хотя да контейнер инжектится, но с точки зрения кода - это тоже самое, что если бы этот контейнер получали из статики какой-то.
 

Yoskaldyr

"Спамер"
Партнер клуба
Для примера еще один член php-fig - contao cms. Как друпал, тоже на симфони компонентах, и даже разбит на бандлы, но опять сервис локатор. Т.е. это уже норма и стандарт де факто. Проверять всех остальных членов php-fig во первых лень, а во вторых бессмысленно, т.к. будет то же самое и пофигу на каких компонентах.

И php-fig это те кто диктует стандарты. Т.е. какой код сейчас, то такие и будут стандарты в будущем :(
 

Adelf

Administrator
Команда форума
Давай начнем с того, что ты попробуешь объяснить почему для обычного проекта сервислокатор плохой? Люди и тесты пишут нормально и реализацию заменить можно.
Потом уже поразмышляем почему в текущих фреймворках повально он по умолчанию идет.
 

WMix

герр M:)ller
Партнер клуба
а использоваться будут классы только первого уровня (например, не прошла валидация и т.п.).
ну не прошла и не прошла, скрипт завершился память отчистилась... хотя 30 обьектов может и многовато, это не критично
 

Yoskaldyr

"Спамер"
Партнер клуба
Давай начнем с того, что ты попробуешь объяснить почему для обычного проекта сервислокатор плохой
С таким подходом можно дойти что и глобальные переменные для обычного проекта норм. а че, тоже просто элементарно подменить на свою реализацию и удобный доступ везде есть и тесты можно делать.

А если по существу, то сервис локатор - ask, а не tell. И все минусы сервис локаторов уже были 100500 раз озвучены везде где только можно.

Я то уже понял что с этим все печально исходя из статистики и дальше будет еще печальнее...
 

Adelf

Administrator
Команда форума
Тем не менее ты постеснялся озвучить их сам. Просто недавно я осознал, что очень сложно протолкнуть идею DI для многих проектов. Банально на хватает аргументов. Мало кому нужна тонкая настройка, типа эта реализация этим классам, а другая - другим. Юнит-тесты почти никто не пишет. Все пишут функциональные или интеграционные и там нет разницы что настроить сервис-локатор или контейнер.
Бравые паладины чистого кода конечно плюются, но бизнес работает :)
 

Yoskaldyr

"Спамер"
Партнер клуба
то сервис локатор - ask, а не tell
Это самый главный и из него следует все остальное. Самое главное что сервис локатор скрывает зависимости конкретного класса, а если говорить практически о том как его используют в большинстве случаев - глобальный магический массив для хранения всего.

Сервис локатор пихают везде как раньше везде пихали синглтоны. Раньше было MyClass::getInstance() сейчас $this->container->get(MyClass::class). И что поменялось? Реализацию тоже можно было менять у синглтона для тестов через MyClass::setInstance(). Т.е. поменялся синтаксис и все. Код остался тот же. Только синглтоны почему-то не устраивали, а обернули в сервис локатор и уже норм. Гуано даже в этом случае остается гуано.

И если из всех моих предыдущих постов не понятно, то я прекрасно понимаю что практически не возможно или возможно но с очень большим оверхедом в плане конфигурации сделать чистый DI и всегда будут компромиссы, но вот народ тупо не использует DI совсем не использует.
 

Yoskaldyr

"Спамер"
Партнер клуба
о забыл о промежуточном варианте контейнер в статике, типа - App::get(MyClass::class). Тоже мрак и тоже легко тестить, ведь легко подменить реализацию...
 

fixxxer

К.О.
Партнер клуба
App::get - это такой fancy Global.
Какой-нибудь global $db тоже легко подменить
 

Yoskaldyr

"Спамер"
Партнер клуба
App::get - это такой fancy Global.
Какой-нибудь global $db тоже легко подменить
Я об этом и говорю! Завернули что-то в более новую обертку, а по сути как было глобалы/синглтоны/статический контейнер, так и осталось!
 

AmdY

Пью пиво
Команда форума
Разница есть, при вызове метода можно по стектрейсу узнать контекст и на основании его подменять реализацию. Даже один раз делал такой костыль для "коробочного" продукта.

Тебе же сразу дали ответ на вопрос по зависимостям. Если компонент не будет заниматься 1000500 задачами, то и столько же зависимостей ему не понадобится как в какой-нибудь упоротой magento 2. Помнится, у них был компонент в двумя десятками инъекций.
К гадалке не ходи — SRP нарушается.
 

Yoskaldyr

"Спамер"
Партнер клуба
@AmdY Где я говорил что 100500 зависимостей в одном компоненте? Я говорил о цепочке зависимостей, это не одно и тоже. Т.е. каждый компонент имеет 3 зависимости максимум (обычно 2), но каждая из этих 2-х зависимостей имеет в свою очередь еще по 2 и т.д. Иногда просто сильно громоздкое описание получается на большом приложении, и классы инстанцируются даже когда не надо, но это пофиг.

Значительно хуже что все и везде используют только сервис локатор в различных его модификациях - вот это уже значительно хуже. И даже @Adelf пишет что это норм. Хотя фактически и по существу это почти ничем не отличается от тех же глобалов.

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

Adelf

Administrator
Команда форума
Ну не норм. Мне приятнее писать класс с явными зависимостями. Но убедить людей очень сложно :)
 

AmdY

Пью пиво
Команда форума
Значительно хуже что все и везде используют только сервис локатор в различных его модификациях - вот это уже значительно хуже. И даже @Adelf пишет что это норм. Хотя фактически и по существу это почти ничем не отличается от тех же глобалов.
Здесь больше проблема и нструментария и легаси. До laravel и autowiring в симфони, я тоже не любит DI с его дикими конфигами. Сейчас это не проблема, но есть старые проекты и инерционность мышления, постепенно все перейдут. Да и для большинства проектов даже new и final в коде не проблема, в 99% никто не мешает модифицировать исходный код.
 

Yoskaldyr

"Спамер"
Партнер клуба
Явно проблема не в легаси а в головах. Типичный пример - друпал. Последние версии (те что на симфони) полностью с нуля же писались и все равно - сервис контейнер. Перечислять можно бесконечно, все равно сервис контейнер для большинства будет проще как и глобалы. Если бы глобалы или статика не сильно порицалась, то и их все еще продолжали бы юзать (хотя что там продолжали - все еще продолжают кому не лень...)
 
Сверху