Updated configuration and DI guides Russian translation [skip ci]

This commit is contained in:
Alexander Makarov
2016-12-08 12:13:02 +03:00
parent 74f72ac663
commit 447c68bef7
2 changed files with 181 additions and 17 deletions

View File

@ -135,6 +135,29 @@ $config = [
За более подробной документацией о настройках свойства `components` в конфигурации приложения обратитесь к главам
[приложения](structure-applications.md) и [Service Locator](concept-service-locator.md).
Начиная с версии 2.0.11, можно настраивать [контейнер зависимостей](concept-di-container.md) через конфигурацию
приложения. Для этого используется свойство `container`:
```php
$config = [
'id' => 'basic',
'basePath' => dirname(__DIR__),
'extensions' => require(__DIR__ . '/../vendor/yiisoft/extensions.php'),
'container' => [
'definitions' => [
'yii\widgets\LinkPager' => ['maxButtonCount' => 5]
],
'singletons' => [
// Конфигурация для единожды создающихся объектов
]
]
];
```
Чтобы узнать о возможных значениях `definitions` и `singletons`, а также о реальных примерах использования,
прочитайте подраздел [более сложное практическое применение](concept-di-container.md#advanced-practical-usage) раздела
[Dependency Injection Container](concept-di-container.md).
### Конфигурации виджетов <span id="widget-configurations"></span>

View File

@ -104,6 +104,138 @@ $container->get('Foo', [], [
> Info: Метод [[yii\di\Container::get()]] третьим аргументом принимает массив конфигурации, которым инициализируется создаваемый объект. Если класс реализует интерфейс [[yii\base\Configurable]] (например, [[yii\base\Object]]), то массив конфигурации передается в последний параметр конструктора класса. Иначе конфигурация применяется уже *после* создания объекта.
Более сложное практическое применение <span id="advanced-practical-usage"></span>
---------------
Допустим, мы работаем над API и у нас есть:
- `app\components\Request`, наследуемый от `yii\web\Request` и реализующий дополнительные возможности.
- `app\components\Response`, наследуемый от `yii\web\Response` с свойством `format`, по умолчанию инициализируемом как `json`.
- `app\storage\FileStorage` и `app\storage\DocumentsReader`, где реализована некая логика для работы с документами в
неком файловом хранилище:
```php
class FileStorage
{
public function __contruct($root) {
// делаем что-то
}
}
class DocumentsReader
{
public function __contruct(FileStorage $fs) {
// делаем что-то
}
}
```
Возможно настроить несколько компонентов сразу передав массив конфигурации в метод
[[yii\di\Container::setDefinitions()|setDefinitions()]] или [[yii\di\Container::setSingletons()|setSingletons()]].
Внутри метода фреймворк обойдёт массив конфигурации и вызовет для каждого элемента [[yii\di\Container::set()|set()]] или
[[yii\di\Container::setSingleton()|setSingleton()]] соответственно.
Формат массива конфигурации следующий:
- Ключ: имя класса, интерфейса или псевдонима. Ключ передаётся в первый аргумент `$class` метода
[[yii\di\Container::set()|set()]].
- Значение: конфигурация для класса. Возможные значения описаны в документации параметра `$definition` метода
[[yii\di\Container::set()|set()]]. Значение передаётся в аргумент `$definition` метода [[set()]].
Для примера, давайте настроим наш контейнер:
```php
$container->setDefinitions([
'yii\web\Request' => 'app\components\Request',
'yii\web\Response' => [
'class' => 'app\components\Response',
'format' => 'json'
],
'app\storage\DocumentsReader' => function () {
$fs = new app\storage\FileStorage('/var/tempfiles');
return new app\storage\DocumentsReader($fs);
}
]);
$reader = $container->get('app\storage\DocumentsReader);
// Создаст объект DocumentReader со всеми зависимостями
```
> Tip: Начиная с версии 2.0.11 контейнер может быть настроен в декларативном стиле через конфигурацию приложения.
Как это сделать ищите в подразделе [Конфигурация приложения](concept-service-locator.md#application-configurations)
раздела [Конфигурации](concept-configurations.md).
Вроде всё работает, но если нам необходимо создать экземпляр класса `DocumentWriter`, придётся скопировать код,
создающий экземпляр`FileStorage`, что, очевидно, не является оптимальным.
Как описано в подразделе [Разрешение зависимостей](#resolving-dependencies), [[yii\di\Container::set()|set()]]
и [[yii\di\Container::setSingleton()|setSingleton()]] могут опционально принимать третьим аргументов параметры
для конструктора. Формат таков:
- Ключ: имя класса, интерфейса или псевдонима. Ключ передаётся в первый аргумент `$class` метода [[yii\di\Container::set()|set()]].
- Значение: массив из двух элементов. Первый элемент передаётся в метод [[yii\di\Container::set()|set()]] вторым
аргументом `$definition`, второй элемент — аргументом `$params`.
Исправим наш пример:
```php
$container->setDefinitions([
'tempFileStorage' => [ // для удобства мы задали псевдоним
['class' => 'app\storage\FileStorage'],
['/var/tempfiles']
],
'app\storage\DocumentsReader' => [
['class' => 'app\storage\DocumentsReader'],
[Instance::of('tempFileStorage')]
],
'app\storage\DocumentsWriter' => [
['class' => 'app\storage\DocumentsWriter'],
[Instance::of('tempFileStorage')]
]
]);
$reader = $container->get('app\storage\DocumentsReader);
// Код будет работать ровно так же, как и в предыдущем примере.
```
Вы могли заметить вызов `Instance::of('tempFileStorage')`. Он означает, что [[yii\di\Container|Container]]
наявно предоставит зависимость, зарегистрированную с именем `tempFileStorage` и передаст её первым аргументом
в конструктор `app\storage\DocumentsWriter`.
> Note: Методы [[yii\di\Container::setDefinitions()|setDefinitions()]] и [[yii\di\Container::setSingletons()|setSingletons()]]
доступны с версии 2.0.11.
Ещё один шаг по оптимизации конфигурации — регистрировать некоторые зависимости как синглтоны. Зависимость, регистрируемая
через метод [[yii\di\Container::set()|set()]] будет созаваться каждый раз при обращении к ней. Некоторые классы не меняют
своего состояния на протяжении всей работы приложения, поэтому могут быть зарегистрированы как синглтоны. Это увеличит
производительность приложения.
Хорошим примером может быть класс `app\storage\FileStorage`, который выполняет некие операции над файловой системой
через простой API: `$fs->read()`, `$fs->write()`. Обе операции не меняют внутреннее состояние класса, поэтому мы можем
создать класс один раз и далее использовать его.
```php
$container->setSingletons([
'tempFileStorage' => [
['class' => 'app\storage\FileStorage'],
['/var/tempfiles']
],
]);
$container->setDefinitions([
'app\storage\DocumentsReader' => [
['class' => 'app\storage\DocumentsReader'],
[Instance::of('tempFileStorage')]
],
'app\storage\DocumentsWriter' => [
['class' => 'app\storage\DocumentsWriter'],
[Instance::of('tempFileStorage')]
]
]);
$reader = $container->get('app\storage\DocumentsReader);
```
### Внедрение зависимости через PHP callback <span id="php-callable-injection"></span>
В данном случае, контейнер будет использовать зарегистрированный PHP callback для создания новых экземпляров класса.
@ -211,13 +343,16 @@ $container->setSingleton('yii\db\Connection', [
Разрешение зависимостей <span id="resolving-dependencies"></span>
----------------------
После регистрации зависимостей, вы можете использовать контейнер внедрения зависимостей для создания новых объектов,
и контейнер автоматически разрешит зависимости их экземпляра и их внедрений во вновь создаваемых объектах. Разрешение зависимостей рекурсивно, то есть
если зависимость имеет другие зависимости, эти зависимости также будут автоматически разрешены.
и контейнер автоматически разрешит зависимости их экземпляра и их внедрений во вновь создаваемых объектах. Разрешение
зависимостей рекурсивно, то есть если зависимость имеет другие зависимости, эти зависимости также будут автоматически
разрешены.
Вы можете использовать [[yii\di\Container::get()]] для создания новых объектов. Метод принимает имя зависимости, которым может быть имя класса, имя интерфейса или псевдоним.
Имя зависимости может быть или не может быть зарегистрировано через `set()` или `setSingleton()`.
Вы можете опционально предоставить список параметров конструктора класса и [конфигурацию](concept-configurations.md) для настройки созданного объекта.
Например,
Вы можете использовать [[yii\di\Container::get()]] для создания или получения объектов. Метод принимает имя зависимости,
которым может быть имя класса, имя интерфейса или псевдоним. Имя зависимости может быть зарегистрировано через
`set()` или `setSingleton()`. Вы можете опционально предоставить список параметров конструктора класса и
[конфигурацию](concept-configurations.md) для настройки созданного объекта.
Например:
```php
// "db" ранее зарегистрированный псевдоним
@ -228,11 +363,14 @@ $engine = $container->get('app\components\SearchEngine', [$apiKey], ['type' => 1
```
За кулисами, контейнер внедрения зависимостей делает гораздо больше работы, чем просто создание нового объекта.
Прежде всего, контейнер, осмотрит конструктор класса, чтобы узнать имя зависимого класса или интерфейса, а затем автоматически разрешит эти зависимости рекурсивно.
Прежде всего, контейнер, осмотрит конструктор класса, чтобы узнать имя зависимого класса или интерфейса, а затем
автоматически разрешит эти зависимости рекурсивно.
Следующий код демонстрирует более сложный пример. Класс `UserLister` зависит от объекта, реализующего интерфейс `UserFinderInterface`; класс `UserFinder` реализует этот интерфейс и зависит от
объекта `Connection`. Все эти зависимости были объявлены через тип подсказки параметров конструктора класса.
При регистрации зависимости через свойство, контейнер внедрения зависимостей позволяет автоматически разрешить эти зависимости и создаёт новый экземпляр `UserLister` простым вызовом `get('userLister')`.
Следующий код демонстрирует более сложный пример. Класс `UserLister` зависит от объекта, реализующего интерфейс
`UserFinderInterface`; класс `UserFinder` реализует этот интерфейс и зависит от объекта `Connection`. Все эти зависимости
были объявлены через тип подсказки параметров конструктора класса. При регистрации зависимости через свойство, контейнер
внедрения зависимостей позволяет автоматически разрешить эти зависимости и создаёт новый экземпляр `UserLister` простым
вызовом `get('userLister')`.
```php
namespace app\models;
@ -291,17 +429,17 @@ $lister = new UserLister($finder);
```
Практическое использование <span id="practical-usage"></span>
Практическое применение <span id="practical-usage"></span>
---------------
Yii создаёт контейнер внедрения зависимостей когда вы подключаете файл `Yii.php` во [входном скрипте](structure-entry-scripts.md)
вашего приложения. Контейнер внедрения зависимостей доступен через [[Yii::$container]]. При вызове [[Yii::createObject()]],
метод на самом деле вызовет метод контейнера [[yii\di\Container::get()|get()]], чтобы создать новый объект.
Как упомянуто выше, контейнер внедрения зависимостей автоматически разрешит зависимости (если таковые имеются) и внедрит их в только что созданный объект.
Поскольку Yii использует [[Yii::createObject()]] в большей части кода своего ядра для создания новых объектов, это означает,
что вы можете настроить глобальные объекты, имея дело с [[Yii::$container]].
Как упомянуто выше, контейнер внедрения зависимостей автоматически разрешит зависимости (если таковые имеются) и внедрит их
получаемый объект. Поскольку Yii использует [[Yii::createObject()]] в большей части кода своего ядра для создания новых
объектов, это означает, что вы можете настроить глобальные объекты, имея дело с [[Yii::$container]].
Например, вы можете настроить по умолчанию глобальное количество кнопок в пейджере [[yii\widgets\LinkPager]]:
Например, давайте настроим количество кнопок в пейджере [[yii\widgets\LinkPager]] по умолчанию глобально:
```php
\Yii::$container->set('yii\widgets\LinkPager', ['maxButtonCount' => 5]);
@ -356,8 +494,11 @@ class HotelController extends Controller
Поскольку зависимости необходимы тогда, когда создаются новые объекты, то их регистрация должна быть сделана
как можно раньше. Ниже приведены рекомендуемые практики:
* Если вы разработчик приложения, то вы можете зарегистрировать зависимости во [входном скрипте](structure-entry-scripts.md) вашего приложения или в скрипте, подключённого во входном скрипте.
* Если вы разработчик распространяемого [расширения](structure-extensions.md), то вы можете зарегистрировать зависимости в загрузочном классе расширения.
* Если вы разработчик приложения, то вы можете зарегистрировать зависимости в конфигурации вашего приложения.
Как это сделать описано в подразделе [Конфигурация приложения](concept-service-locator.md#application-configurations)
раздела [Конфигурации](concept-configurations.md).
* Если вы разработчик распространяемого [расширения](structure-extensions.md), то вы можете зарегистрировать зависимости
в загрузочном классе расширения.
Итог <span id="summary"></span>