Подтвердить что ты не робот

Что такое Laravel IoC Container простыми словами?

Кто-нибудь может объяснить инъекцию зависимостей и контейнер IoC простыми и легкими словами, поскольку я начинаю пользоваться laravel. спасибо

4b9b3361

Ответ 1

Ответ стал длиннее, чем я хотел, чтобы он был в первую очередь. Я включил немного справочной информации. Тем не менее, если вы ищете краткосрочные объяснения, прочитайте первый абзац IoC-Container и смелые отрывки.

Инъекция зависимостей

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

<?php

class DatabaseWriter {

    protected $db;

    public function __construct(DatabaseAdapter $db)
    {
        $this->db = $db;
    }

    public function write()
    {
        $this->db->query('...');
    }

}

Вы можете видеть, что нам нужен конструктор классов a DatabaseAdapter экземпляр, который должен быть передан. Поскольку мы делаем это в конструкторе, объект этого класса не может быть создан без него: Мы вводим зависимость. Теперь, когда мы знаем, что DatabaseAdapter всегда существует внутри класса, мы можем легко положиться на него.

Метод write() просто вызывает методы на адаптере, поскольку мы определенно знаем, что он существует, потому что мы использовали DI.

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

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

Оставляя в стороне тот факт, что с помощью Dependency Injection вы сможете легко тестировать свои классы, поскольку вы можете просто издеваться над зависимостями, которые вряд ли возможны с жестко закодированными зависимостями.

Три типа инжекций зависимостей

Инъекция конструктора

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

Инжекция сеттера

Этот тип использует специальные методы для встраивания зависимостей. Вместо использования конструктора. Преимущество использования Setter Injection заключается в том, что вы можете добавлять зависимости к объекту после его создания. Он обычно используется для дополнительных зависимостей. Setter Injection также отлично подходит для вашего конструктора и имеет ваши зависимости только в тех случаях, когда они вам нужны.

<?php

class RegisterUserService {

    protected $logger;

    public function setLogger( Logger $logger )
    {
        $this->logger = $logger;
    }

    public function registerUser()
    {
        // Do stuff to register the user
        if($this->logger)
            $this->logger->log("User has been registered");
    }

}

$service = new RegisterUserService;
$service->registerUser(); // Nothing is Logged

$service->setLogger(new ConcreteLogger);
$service->registerUser(); // Now we log

Объект может быть создан без каких-либо зависимостей. Существует метод ввода зависимости (setLogger()), который можно назвать необязательным. Теперь до реализации методов либо использовать зависимость, либо нет (если она не установлена).

Стоит отметить, что нужно быть осторожным с Setter Injection. Вызов методов или доступ к атрибутам в зависимости, которые еще не были введены, приведет к неприятному Fatal error: Call to a member function XXX() on a non-object. Поэтому при каждом обращении к зависимостям он сначала должен быть проверен нуль. Гораздо более эффективным способом было бы использовать Нулевой шаблон объекта и переместить зависимость в конструктор (в качестве необязательного аргумента, если ничего не передано нулевым объектом создается внутри класса)

Инъекция интерфейса

Идея инъекции интерфейса в основном заключается в том, что метод для инъекции зависимости определяется в интерфейсе. Класс, который будет нуждаться в зависимости, должен реализовать интерфейс. Таким образом обеспечивается, что необходимая зависимость может быть правильно введена в зависимый объект. Это более строгая форма ранее объясненной инъекции Setter.

<?php

interface Database {

    public function query();

}

interface InjectDatabaseAccess {

    // The user of this interface MUST provide
    // a concrete of Database through this method
    public function injectDatabase( Database $db );

}

class MySQL implements Database {

    public function query($args)
    {
        // Execute Query
    }

}

class DbDoer implements InjectDatabaseAccess {

    protected $db;

    public function injectDatabase( Database $db )
    {
        $this->db = $db;
    }

    public function doSomethingInDb($args)
    {
        $this->db->query();
    }

}

$user = new DbDoer();
$user->injectDatabase( new MySQL );
$user->doSomethingInDb($stuff);

Значимость интерфейса Injection открыта для спора. Лично я никогда не использовал его. Я предпочитаю инжекцию конструктора над ним. Это позволяет мне выполнить ту же задачу без необходимости дополнительных интерфейсов на стороне форсунок.

Инверсия зависимостей

Вместо того, чтобы зависеть от конкретного примера, мы также можем зависеть от абстракций.

<?php

class DatabaseWriter {

    protected $db;

    public function __construct(DatabaseAdapterInterface $db)
    {
        $this->db = $db;
    }

    public function write()
    {
        $this->db->query('...');
    }

}

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

Убедитесь, что вы получили это, потому что это основная концепция IoC-Container.

Контейнер IoC

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

IoC-Container - это компонент, который знает, как создаются экземпляры и знает все их базовые зависимости и способы их решения.

Если мы возьмем наш пример выше, представьте, что сам DatabaseAdapter имеет свои собственные зависимости.

class ConcreteDatabaseAdapter implements DatabaseAdapterInterface{

    protected $driver;

    public function __construct(DatabaseDriverInterface $driver)
    {
        $this->driver = $driver;
    }

}

Итак, чтобы иметь возможность использовать DatabaseAdapter, вам нужно передать в качестве примера абстракцию DatabaseDriverInterface в качестве зависимости.

Но ваш класс DatabaseWriter не знает об этом, и он не должен. DatabaseWriter не должен заботиться о том, как работает DatabaseAdapter, он должен заботиться только о том, что передается DatabaseAdapter, а не как его нужно создать. То, что IoC-Container пригодится.

App::bind('DatabaseWriter', function(){
    return new DatabaseWriter(
        new ConcreteDatabaseAdapter(new ConcreteDatabaseDriver)
    );
});

Как я уже сказал, сам DatabaseWriter ничего не знает о зависимостях зависимостей. Но IoC-Container знает все о них, а также знает, где их найти. Таким образом, в конце концов, когда будет создан экземпляр класса DatabaseWriter, сначала IoC-Container задается , как его нужно создать. Это то, что делает IoC-Container.

Проще говоря (если вы в шаблонах дизайна). Это немного комбинация контейнера для инъекций зависимостей (который я уже объяснял выше) и Locator..

Ответ 2

подумайте, что у вас есть класс Car, например, ниже:

    class Car 
    {

        protected $wheels;
        protected $engine;

        public function __construct()
        {
            $this->engine = new Engine('BMW Engine');

            $this->wheels  = array(
                               new Wheel('some Wheel Brand'),
                               new Wheel('some Wheel Brand'),
                               new Wheel('some Wheel Brand'),
                               new Wheel('some Wheel Brand')
                              );
        }

        public function go()
        {
            //do fun stuff here
        }
   }

Теперь подумайте о повторном использовании кода и, например, хотите иметь еще один класс автомобилей, который предназначен для компании Toyota. вы должны написать точно выше кода с небольшим редактированием, как показано ниже:

class AnotherCar 
{

    protected $wheels;
    protected $engine;

    public function __construct()
    {
        $this->engine = new Engine('Toyota Engine');
         $this->wheels  = array(new Wheel('some Wheel Brand'),
                           new Wheel('some Wheel Brand'),
                           new Wheel('some Wheel Brand'),
                           new Wheel('some Wheel Brand'));
    }

    public function go()
    {
        //do fun stuff here
    }


}

ваш код будет расти и расти и будет больно, если вы не будете использовать DI (Injection Dependency) или IoC (Inversion Of Control).

позволяет говорить о том, какие проблемы с кодом выше: 1- его нельзя использовать повторно. 2- он не заботится о производительности (объем кода в вашем Ram,...) 3- ваш код растет, и вы не поймете его сами через некоторое время. ...

поэтому позволяет использовать DI и решать проблему

class Car 
{


    protected $wheels;
    protected $engine;

    public function __construct($myWheels , $myEngine)
    {
       $this->engine = $myEngine;
       $this->wheels  = $myWheels; 
    }

    public function go()
    {
        //do fun stuff here
    }
}

теперь вы легко можете создать каждый объект автомобиля выше класса Car, как показано ниже:

$BMW = new Car (new Engine('BMW' , array(new Wheel('wheel beand') ,new Wheel('wheel beand') ,new Wheel('wheel beand') ,new Wheel('wheel beand') )));

см.! намного легче! также ваш код является много читаемым и многоразовым!

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

это будет мешать вам иметь в виду, работая над тем, какой класс зависит от того, какие классы и... это где МОК приходит и решает проблемы.

Рисунок IOC или, может быть, решение не очень легко понять, вы должны столкнуться с проблемами, о которых я говорил ранее. МОК нуждается в больших проектах! в java Spring является одним из самых известных контейнеров МОК и что делает МОК??? он содержит множество конфигурационных файлов (или некоторые конфигурации контейнеров IOC находятся в исходном коде, а также некоторые из них имеют пользовательский интерфейс для конфигураций) и эти конфиги содержат отношение между классом и какой класс для загрузки зависят от того, какие классы это также большая помощь для ленивой загрузки! просто когда вам нужно загрузить объект, вы загружаете его зависимости!