За последние 24 часа нас посетили 17938 программистов и 1582 робота. Сейчас ищет 1281 программист ...

Как добавить классы в сервис-провайдеры

Тема в разделе "Laravel", создана пользователем pr0n1x, 10 окт 2018.

Метки:
  1. pr0n1x

    pr0n1x Активный пользователь

    С нами с:
    30 мар 2006
    Сообщения:
    486
    Симпатии:
    2
    Адрес:
    Киев
    Здравствуйте, не могу понять как работают сервис-провайдеры в Laravel.

    Мне нужно реализовать свой функционал для моего проекта. Допустим у меня есть такой функционал:

    PHP:
    1. interface FileSizeInterface {
    2.     public function showFileSize();
    3. }
    4.  
    5. abstract class ParamHandler {
    6.     protected $source;
    7.     protected $params = [];
    8.  
    9.     public function __construct($source) {
    10.         $this->source = $source;
    11.     }
    12.  
    13.     public function addParam ($key, $value) {
    14.         $this->params[$key] = $value;
    15.     }
    16.  
    17.     public static function getInstance($filename) {
    18.         if (preg_match("/\.xml$/i", $filename)) {
    19.             return new XmlParamHandler($filename);
    20.         }
    21.         return new TextParamHandler($filename);
    22.     }
    23.  
    24.     abstract function write();
    25.     abstract function read();
    26. }
    27.  
    28. class XmlParamHandler extends ParamHandler implements FileSizeInterface {
    29.     function write() {
    30.         // Запись в формате XML
    31.     }
    32.  
    33.     function read() {
    34.         // Чтение из XML файла
    35.     }
    36.  
    37.     function showFileSize() {
    38.         // Показать информацию
    39.     }
    40. }
    41.  
    42. class TextParamHandler extends ParamHandler implements FileSizeInterface {
    43.     function write() {
    44.         // Запись в текстовый файл
    45.     }
    46.  
    47.     function read() {
    48.         // Чтение из текстового файла
    49.     }
    50.  
    51.     function showFileSize() {
    52.         // Показать информацию
    53.     }
    54. }
    Как все это запихнуть в сервис-контейнер? И вообще нужно ли его туда пихать если я могу все это положить в отдельную папку App и подключать файлы через use
     
  2. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.583
    Симпатии:
    1.761
    @pr0n1x, нужно, чтоб отделить создание класса от использования. И чтоб он автоматически в контроллеры инъектился. Читай раздел Dependency Injection документации. А service provider как раз нужен, чтоб засунуть в контейнер все зависимости. В небольших проектах достаточно в AppServiceProvider, который при создании проекта появляется, запихнуть. Вот фрагмент из моего кода:
    PHP:
    1. <?php
    2.  
    3. namespace App\Providers;
    4.  
    5. use App\Observers\UserObserver;
    6. use App\Services\Login\FakeLoginCodeGenerator;
    7.  
    8. use Illuminate\Support\ServiceProvider;
    9.  
    10. class AppServiceProvider extends ServiceProvider
    11. {
    12.     /**
    13.      * Bootstrap any application services.
    14.      *
    15.      * @return void
    16.      */
    17.     public function boot()
    18.     {
    19.         User::observe(UserObserver::class);
    20.     }
    21.  
    22.     /**
    23.      * Register any application services.
    24.      *
    25.      * @return void
    26.      */
    27.     public function register()
    28.     {
    29.         $this->app->singleton(ILoginCodeGenerator::class, FakeLoginCodeGenerator::class);
    30.         // .....
    31.     }
    32. }
    Реально там больше, я подсократил
    --- Добавлено ---
    Потом я в контроллере пишу
    PHP:
    1. class LoginController {
    2.     function sendCode(ILoginCodeGenerator $codeGen) {
    3.    }
    4. }
    И мне Laravel сам передаёт тот генератор, который я в контейнер положил, без моего участия
     
  3. pr0n1x

    pr0n1x Активный пользователь

    С нами с:
    30 мар 2006
    Сообщения:
    486
    Симпатии:
    2
    Адрес:
    Киев
    Зачем создавать экземпляры классов если их не использовать, чтобы они просто висели в контейнере? Мой класс должен отработать в методе контроллера, сгенерировать мне json и все. Почему предпочтительней запихнуть его в контейнер вместо того, чтобы подключить его через use и использовать там где мне нужно?
     
  4. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.583
    Симпатии:
    1.761
    Контейнер не создаёт экземпляр, пока не попросишь. Причина - убрать создание зависимостей из кода класса, который их использует, не дублировать это создание, если класс нужен в нескольких местах, возможность подставлять разные реализации одного интерфейса. В моём случае, когда я закончу тестировать, я просто в провайдере заменю FakeLoginCodeGenerator на RealCodeGenerator, а контроллер трогать не понадобится. В общем, читаем про SOLID, инверсию зависимостей, паттерны и др. А ещё в некоторых случаях экземпляр требует более сложной инициализации, чем new ClassName, тогда писать это в контроллере - засорять свой код.

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

    Taktreba Активный пользователь

    С нами с:
    11 янв 2017
    Сообщения:
    543
    Симпатии:
    132
    мне тоже интересно
     
  6. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.583
    Симпатии:
    1.761
  7. pr0n1x

    pr0n1x Активный пользователь

    С нами с:
    30 мар 2006
    Сообщения:
    486
    Симпатии:
    2
    Адрес:
    Киев
    Статьи хорошие, но практически со всем, что там написано я знаком, использую это в своих классах, но все равно я не монимаю, зачем и как это используется в ларавел.