Laravel по-русски

Русское сообщество разработки на PHP-фреймворке Laravel.

Ты не вошёл. Вход тут.

#1 23.10.2016 22:47:00

Александр

Зачем использовать сервиспровайдер?

Привет. Поясните, для чего нужно загружать свои классы с помощью сервиспровайдера? Можно же создать папку в app, например libraries и в этой папке размещать свои классы, например Parser.php. Главное в каждом классе указывать неймспейс этой папки, то есть namespace App\libraries. Тогда в приложении становится доступен этот класс с помощью директивы use App\libraries\Parser. Причем доступен со всеми фишками лары, то есть, подключив таким образом этот класс в контроллере, можно использовать внедрение зависимостей через сервисконтейнер, например
public function __construct(Parser $parser) {}
Вот собственно вопрос, зачем регистрировать свой сервиспровайдер и какая разница будет между загрузкой таким образом и загрузкой через сервиспровайдер?

#2 24.10.2016 04:40:45

Re: Зачем использовать сервиспровайдер?

Имхо, таким образом осуществляется подмена классов (полиморфизм т.е.). Например написал ты интерфейс для онлайн оплаты товара (рассылки смс и т.д.). Реализуешь их с помощью конкретных классов (например для яндекса, для монеты, для API конкретного банка). Заказчик за ,3 секунды до подписания акта сдачи проекта решает изменить способ оплаты с яндеса на монету (или наоборот или еще на что-то). Если есть готовая реализация ты просто в одном месте программы изменяешь строчку и все готово.

А если внедрять напрямую класс в метод (конструктор) то ты жестко привязан к конкретной реализации. Можно конечно быстренько найти все use и внедения и заменить (тут главное - не пропустить где-то, и не оставить старую реализацию, на что заказчик может обидеться и реализовать свою версию секаса smile, репутация опять-таки) на нужное. Но это нарушает всемирную гармонию энергии big_smile

Ну а обычные модели и прочие вещи, которые точно не будут меняться (т.е. не реализуют интерфейс, который можно вот так просто подменить) внедряются через сервис-контейнер.

Повторюсь - это то, что я понял читая доки.

Не в сети

#3 24.10.2016 22:49:12

Александр

Re: Зачем использовать сервиспровайдер?

Понятно. Еще попутный вопрос. Он вроде как косвенно относится к сервиспровайдерам, но на сей раз про контракты) Контракты в laravel (они же, как я понял, обычные интерфейсы) нужны только для того, чтобы внедрять зависимости через конструктор, так или нет? Так, например, создал я контакт PaymentContract. Затем в сервиспровайдере я делаю привязку какой-то реализации к этому контракту
$this->app->bind('App\Contracts\PaymentContract', 'App\Services\Webmoney');
И теперь в контроллере я делаю внедрение зависимости через этот контракт, и сервисконтейнер сам подставляет нужную реализацию, забинденную в сервиспровайдере:
public function PaymentMethod(PaymentContract $payment)
{
...
}
Отлично. Мой код имеет слабую связность, и я могу изменить способ оплаты просто изменив реализацию в сервисконтейнере. Ну и собственно к сути вопроса. Я могу переписать код в сервиспровайдере следующим образом:
$this->app->bind('Payment', function(){
    return new \App\Services\Webmoney();
});
и код контроллера:
public function PaymentMethod()
{
    $payment = app()->make('Payment');
}
В результате в обоих случаях в $payment получается экземпляр привязанного в сервиспровайдере класса, и реализация легко меняется. Только во втором случае необходимость в интерфейсе отпадает. Тогда зачем использовать контракты (интерфейсы) в коде? И какой вариант более правильный?

#4 25.10.2016 04:15:49

Re: Зачем использовать сервиспровайдер?

Ну, если я верно понял суть вопроса, то суть, интерфейса состоит в том, что все классы реализующие интерфейс имеют одинаковый интерфейс smile

Ну например в одной реализации WebMoney() есть метод какой-то, узнать оплатил или передумал чел, и назван он к примеру - check($id), где $id - идентификатор транзакции в webmoney. И вот сайт весело пользует это дело. Но тут захотелось работать с PayPal ну или еще чего. Реализуем это дело, но в этот раз называем метод проверки - check(), т.е. предполагается, что ид транзакции был задан где-то в другом месте. Далее меняем привязку в контейнере и с удивлением обнаруживается, что код сломался, ибо старый код (ответственный за вызов check) не знает (правда реализация PayPal может сама где-то его брать, а что если этих разных реализаций - штук 20 и каждая из них реализована по-своему?), что ид надо задавать где-то в другом месте и пытается с этим работать. Получаем ошибку.

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

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

Не в сети

#5 25.10.2016 10:49:13

Александр

Re: Зачем использовать сервиспровайдер?

mavsan, спасибо! Примерно так и представлял себе все это дело. Значит ли это, что каждый собственный класс в моем приложении должен реализовывать какой-то интерфейс или это будет усложнять разработку в некоторых случаях? В каких случаях стоит применять интерфейсы, а в каких нет? Про проектирование очень интересно, может посоветуешь какую-нибудь литературу, буду благодарен. И про инстанцирование интересно все же, есть ли разница, внедрять зависимости через конструктор или метод класса, или же делать это внутри метода, вынимая из сервисконтейнера? И, если есть разница, какой из методов более лучший и по чему?

#6 25.10.2016 16:25:12

Роман

Re: Зачем использовать сервиспровайдер?

Звучит все конечно отлично, но что-то уж очень редко вижу код которые следует этим принципам, половина seniors теряет создание когда слышат enterprise patterns вообще, не говоря уже об принципах SOLID

#7 25.10.2016 17:02:36

Re: Зачем использовать сервиспровайдер?

"Когда меня спрашивают для чего нужны сервис-провайдеры в Laravel, я пожимаю плечами и говорю: если вы не знаете зачем они нужны, значит они вам не нужны. Если вы пишите и строите код так, как это описано во всех мануалах, скорее всего вам хватит одного провайдера на всё приложение, и он уже есть сразу. И не надо парить мозг себе и людям. Просто забейте на это все." (C)

Не в сети

Подвал раздела