[Статья Мартина Фаулера](http://martinfowler.com/articles/injection.html) хорошо объясняет, почему контейнер внедрения зависимостей является полезным. Здесь, преимущественно, будет объясняться использование контейнера внедрения зависимостей, предоставляемого в Yii.
Вы можете использовать [[yii\di\Container::set()]] для регистрации зависимостей. При регистрации требуется имя зависимости, а так же определение зависимости.
Именем зависимости может быть имя класса, интерфейса или алиас, так же определением зависимости может быть имя класса, конфигурационным массивом, или PHP calback'ом.
```php
$container = new \yii\di\Container;
// регистрация имени класса, как есть. это может быть пропущено.
$container->set('yii\db\Connection');
// регистрация интерфейса
// Когда класс зависит от интерфейса, соответствующий класс
// будет использован в качестве зависимости объекта
// регистрация алиаса. Вы можете использовать $container->get('foo')
// для создания экземпляра Connection
$container->set('foo', 'yii\db\Connection');
// Регистрация класса с конфигурацией. Конфигурация
// будет применена при создании экземпляра класса через get()
$container->set('yii\db\Connection', [
'dsn' => 'mysql:host=127.0.0.1;dbname=demo',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
]);
// регистрация алиаса с конфигурацией класса
// В данном случае, параметр "class" требуется для указания класса
$container->set('db', [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=127.0.0.1;dbname=demo',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
]);
// регистрация PHP callback'a
// Callback будет выполняться каждый раз при вызове $container->get('db')
$container->set('db', function ($container, $params, $config) {
return new \yii\db\Connection($config);
});
// регистрация экземпляра компонента
// $container->get('pageCache') вернёт тот же экземпляр при каждом вызове
$container->set('pageCache', new FileCache);
```
> Подсказка: Если имя зависимости такое же, как и определение соответствующей зависимости, то её повторная регистрация в контейнере внедрения зависимостей не нужна.
Зависимость, зарегистрированная через `set()` создаёт экземпляр каждый раз, когда зависимость необходима.
Вы можете использовать [[yii\di\Container::setSingleton()]] для регистрации зависимости, которая создаст только один экземпляр:
После регистрации зависимостей, вы можете использовать контейнер внедрения зависимостей для создания новых объектов,
и контейнер автоматически разрешит зависимости их экземпляра и их внедрений во вновь создаваемых объектах. Разрешение зависимостей рекурсивно, то есть
если зависимость имеет другие зависимости, эти зависимости также будут автоматически разрешены.
Вы можете использовать [[yii\di\Container::get()]] для создания новых объектов. Метод принимает имя зависимости, которым может быть имя класса, имя интерфейса или псевдоним.
Имя зависимости может быть или не может быть зарегистрировано через `set()` или `setSingleton()`.
Вы можете опционально предоставить список параметров конструктора класса и [конфигурацию](concept-configurations.md) для настройки созданного объекта.
Например,
```php
// "db" ранее зарегистрированный псевдоним
$db = $container->get('db');
// эквивалентно: $engine = new \app\components\SearchEngine($apiKey, ['type' => 1]);
За кулисами, контейнер внедрения зависимостей делает гораздо больше работы, чем просто создание нового объекта.
Прежде всего, контейнер, осмотрит конструктор класса, чтобы узнать имя зависимого класса или интерфейса, а затем автоматически разрешит эти зависимости рекурсивно.
Следующий код демонстрирует более сложный пример. Класс `UserLister` зависит от объекта, реализующего интерфейс `UserFinderInterface`; класс `UserFinder` реализует этот интерфейс и зависит от
объекта `Connection`. Все эти зависимости были объявлены через тип подсказки параметров конструктора класса.
При регистрации зависимости через свойство, контейнер внедрения зависимостей позволяет автоматически разрешить эти зависимости и создаёт новый экземпляр `UserLister` простым вызовом `get('userLister')`.
```php
namespace app\models;
use yii\base\Object;
use yii\db\Connection;
use yii\di\Container;
interface UserFinderInterface
{
function findUser();
}
class UserFinder extends Object implements UserFinderInterface
{
public $db;
public function __construct(Connection $db, $config = [])
{
$this->db = $db;
parent::__construct($config);
}
public function findUser()
{
}
}
class UserLister extends Object
{
public $finder;
public function __construct(UserFinderInterface $finder, $config = [])
Yii создаёт контейнер внедрения зависимостей когда вы подключаете файл `Yii.php` во [входном скрипте](structure-entry-scripts.md)
вашего приложения. Контейнер внедрения зависимостей доступен через [[Yii::$container]]. При вызове [[Yii::createObject()]],
метод на самом деле вызовет метод контейнера [[yii\di\Container::get()|get()]], чтобы создать новый объект.
Как упомянуто выше, контейнер внедрения зависимостей автоматически разрешит зависимости (если таковые имеются) и внедрит их в только что созданный объект.
Поскольку Yii использует [[Yii::createObject()]] в большей части кода своего ядра для создания новых объектов, это означает,
что вы можете настроить глобальные объекты, имея дело с [[Yii::$container]].
Например, вы можете настроить по умолчанию глобальное количество кнопок в пейджере [[yii\widgets\LinkPager]]:
Теперь, если вы вызовете в представлении виджет, используя следующий код, то свойство `maxButtonCount` будет инициализировано, как 5, вместо значения по умолчанию 10, как это определено в классе.
```php
echo \yii\widgets\LinkPager::widget();
```
Хотя, вы всё ещё можете переопределить установленное значение через контейнер внедрения зависимостей:
Теперь, если вы попытаетесь получить доступ к контроллеру снова, то экземпляр `app\components\BookingService` будет создан и введён в качестве 3-го параметра конструктора контроллера.
Поскольку зависимости необходимы тогда, когда создаются новые объекты, то их регистрация должна быть сделана
как можно раньше. Ниже приведены рекомендуемые практики:
* Если вы разработчик приложения, то вы можете зарегистрировать зависимости во [входном скрипте](structure-entry-scripts.md) вашего приложения или в скрипте, подключённого во входном скрипте.
* Если вы разработчик распространяемого [расширения](structure-extensions.md), то вы можете зарегистрировать зависимости в загрузочном классе расширения.