Browse Source

Update concept-di-container.md

tags/2.0.16
cuiliang 7 years ago committed by GitHub
parent
commit
956feac7a4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 104
      docs/guide-zh-CN/concept-di-container.md

104
docs/guide-zh-CN/concept-di-container.md

@ -1,13 +1,13 @@
依赖注入容器
==========
依赖注入容器(Dependency Injection Container)
===========================================
依赖注入(Dependency Injection,DI)容器就是一个对象,它知道怎样初始化并配置对象及其依赖的所有对象。
[Martin 的文章](http://martinfowler.com/articles/injection.html) 已经解释了 DI 容器为什么很有用。
这里我们主要讲解 Yii 提供的 DI 容器的使用方法。
依赖注入 <span id="dependency-injection"></span>
-------
依赖注入(Dependency Injection) <span id="dependency-injection"></span>
-----------------------------
Yii 通过 [[yii\di\Container]] 类提供 DI 容器特性。
它支持如下几种类型的依赖注入:
@ -18,7 +18,7 @@ Yii 通过 [[yii\di\Container]] 类提供 DI 容器特性。
* PHP 回调注入.
### 构造方法注入 <span id="constructor-injection"></span>
### 构造方法注入(Constructor Injection) <span id="constructor-injection"></span>
在参数类型提示的帮助下,DI 容器实现了构造方法注入。当容器被用于创建一个新对象时,
类型提示会告诉它要依赖什么类或接口。
@ -40,7 +40,7 @@ $foo = new Foo($bar);
```
### 方法注入 <span id="method-injection"></span>
### 方法注入(Method Injection) <span id="method-injection"></span>
通常,类的依赖关系传递给构造函数,并且在整个生命周期中都可以在类内部使用。
通过方法注入,可以提供仅由类的单个方法需要的依赖关系,
@ -70,7 +70,7 @@ $obj = new MyClass(/*...*/);
Yii::$container->invoke([$obj, 'doSomething'], ['param1' => 42]); // $something will be provided by the DI container
```
### Setter 和属性注入 <span id="setter-and-property-injection"></span>
### Setter 和属性注入(Setter and Property Injection) <span id="setter-and-property-injection"></span>
Setter 和属性注入是通过[配置](concept-configurations.md)提供支持的。
当注册一个依赖或创建一个新对象时,你可以提供一个配置,
@ -109,7 +109,7 @@ $container->get('Foo', [], [
否则,将在创建对象*后*应用该配置。
### PHP 回调注入 <span id="php-callable-injection"></span>
### PHP 回调注入(PHP Callable Injection) <span id="php-callable-injection"></span>
在这种情况下,容器将使用已注册的 PHP 回调来构建类的新实例。
每次调用 [[yii\di\Container::get()]] ,相应的回调将被调用。
@ -119,7 +119,7 @@ $container->get('Foo', [], [
```php
$container->set('Foo', function () {
$foo = new Foo(new Bar);
// ... other initializations ...
// ... 其他初始化 ...
return $foo;
});
@ -134,7 +134,7 @@ class FooBuilder
public static function build()
{
$foo = new Foo(new Bar);
// ... other initializations ...
// ... 其他初始化 ...
return $foo;
}
}
@ -147,8 +147,8 @@ $foo = $container->get('Foo');
这样做的话,想要配置 `Foo` 类的人不再需要知道它是如何构建的。
注册依赖关系 <span id="registering-dependencies"></span>
------------------------
注册依赖关系(Registering Dependencies) <span id="registering-dependencies"></span>
------------------------------------
可以用 [[yii\di\Container::set()]] 注册依赖关系。注册会用到一个依赖关系名称和一个依赖关系的定义。
依赖关系名称可以是一个类名,一个接口名或一个别名。
@ -216,8 +216,8 @@ $container->setSingleton('yii\db\Connection', [
```
解决依赖关系 <span id="resolving-dependencies"></span>
----------------------
解决依赖关系(Resolving Dependencies) <span id="resolving-dependencies"></span>
----------------------------------
注册依赖关系后,就可以使用 DI 容器创建新对象了。容器会自动解决依赖关系,
将依赖实例化并注入新创建的对象。依赖关系的解决是递归的,
@ -307,8 +307,8 @@ $lister = new UserLister($finder);
```
实践中的运用 <span id="practical-usage"></span>
---------------
实践中的运用(Practical Usage) <span id="practical-usage"></span>
---------------------------
当在应用程序的[入口脚本](structure-entry-scripts.md)中引入 `Yii.php` 文件时,
Yii 就创建了一个 DI 容器。这个 DI 容器可以通过 [[Yii::$container]] 访问。
@ -372,16 +372,16 @@ class HotelController extends Controller
现在如果你再次访问这个控制器,一个 `app\components\BookingService`
的实例就会被创建并被作为第三个参数注入到控制器的构造器中。
高级实用性 <span id="advanced-practical-usage"></span>
---------
高级实用性(Advanced Practical Usage) <span id="advanced-practical-usage"></span>
-----------------------------------
比如说我们在 API 应用方面工作:
- `app\components\Request` class that extends `yii\web\Request` and provides additional functionality
- `app\components\Response` class that extends `yii\web\Response` and should have `format` property
set to `json` on creation
- `app\storage\FileStorage` and `app\storage\DocumentsReader` classes that implement some logic on
working with documents that are located in some file storage:
- `app\components\Request` 类继承了 `yii\web\Request` 并提供了额外的功能
- `app\components\Response` 类继承了 `yii\web\Response` 并且在创建时应该将 `format`
属性设置为 `json`
- `app\storage\FileStorage` `app\storage\DocumentsReader`
用于处理位于某些文件存储中的文档的某些逻辑:
```php
class FileStorage
@ -399,18 +399,18 @@ class HotelController extends Controller
}
```
It is possible to configure multiple definitions at once, passing configuration array to
[[yii\di\Container::setDefinitions()|setDefinitions()]] or [[yii\di\Container::setSingletons()|setSingletons()]] method.
Iterating over the configuration array, the methods will call [[yii\di\Container::set()|set()]]
or [[yii\di\Container::setSingleton()|setSingleton()]] respectively for each item.
可以一次配置多个定义,将配置数组传递给
[[yii\di\Container::setDefinitions()|setDefinitions()]] 或 [[yii\di\Container::setSingletons()|setSingletons()]] 方法。
遍历配置数组,将分别为每个对象分别调用 [[yii\di\Container::set()|set()]]
或 [[yii\di\Container::setSingleton()|setSingleton()]] 方法。
配置数组格式为:
- `key`: class name, interface name or alias name. The key will be passed to the
[[yii\di\Container::set()|set()]] method as a first argument `$class`.
- `value`: the definition associated with `$class`. Possible values are described in [[yii\di\Container::set()|set()]]
documentation for the `$definition` parameter. Will be passed to the [[set()]] method as
the second argument `$definition`.
- `key`:类名称,接口名称或别名。 该 key 将作为第一个参数
`$class` 传递给 [[yii\di\Container::set()|set()]] 方法。
- `value`:与 `$class` 关联的定义。`$definition` 参数的值可能在 [[yii\di\Container::set()|set()]]
文档中描述。`$definition` 将作为第二个参数传递给 [[set()]]
方法。
例如,让我们配置我们的容器以遵循上述要求:
@ -428,32 +428,32 @@ $container->setDefinitions([
]);
$reader = $container->get('app\storage\DocumentsReader);
// Will create DocumentReader object with its dependencies as described in the config
// 将按照配置中的描述创建 DocumentReader 对象及其依赖关系
```
> Tip: Container may be configured in declarative style using application configuration since version 2.0.11.
Check out the [Application Configurations](concept-configurations.md#application-configurations) subsection of
the [Configurations](concept-configurations.md) guide article.
> Tip: 自 2.0.11 版以后,可以使用应用程序配置以声明式风格配置容器。
查看[配置](concept-configurations.md)指南文章的
[应用程序配置](concept-configurations.md#application-configurations)小节。
Everything works, but in case we need to create `DocumentWriter` class,
we shall copy-paste the line that creates `FileStorage` object, that is not the smartest way, obviously.
一切正常,但如果我们需要创建 `Document Writer` 类,
我们将复制粘贴创建 `FileStorage` 对象的行,这显然不是最聪明的方式。
As described in the [Resolving Dependencies](#resolving-dependencies) subsection, [[yii\di\Container::set()|set()]]
and [[yii\di\Container::setSingleton()|setSingleton()]] can optionally take dependency's constructor parameters as
a third argument. To set the constructor parameters, you may use the following configuration array format:
如 [解决依赖关系](#resolving-dependencies) 子节中所述,[[yii\di\Container::set()|set()]]
和 [[yii\di\Container::setSingleton()|setSingleton()]] 可以选择将依赖项的构造函数参数作为第三个参数。
要设置构造函数参数,可以使用以下配置数组格式:
- `key`: class name, interface name or alias name. The key will be passed to the
[[yii\di\Container::set()|set()]] method as a first argument `$class`.
- `value`: array of two elements. The first element will be passed to the [[yii\di\Container::set()|set()]] method as the
second argument `$definition`, the second one — as `$params`.
- `key`:类名称,接口名称或别名。该 key 将作为第一个参数
`$class` 传递给 [[yii\di\Container::set()|set()]] 方法。
- `value`:两个元素的数组。第一个元素将传递给 [[yii\di\Container::set()|set()]] 方法
作为第二个参数 `$definition`,第二个元素为 `$params`
让我们来修改我们的例子:
```php
$container->setDefinitions([
'tempFileStorage' => [ // we've created an alias for convenience
'tempFileStorage' => [ // 我们为了方便创建了一个别名
['class' => 'app\storage\FileStorage'],
['/var/tempfiles'] // could be extracted from some config files
       ['/var/tempfiles'] // 可以从一些配置文件中获取
],
'app\storage\DocumentsReader' => [
['class' => 'app\storage\DocumentsReader'],
@ -466,7 +466,7 @@ $container->setDefinitions([
]);
$reader = $container->get('app\storage\DocumentsReader);
// Will behave exactly the same as in the previous example.
// 将与前面示例中的行为完全相同。
```
你可能会注意到 `Instance::of('tempFileStorage')` 符号。这意味着,[[yii\di\Container|Container]]
@ -507,8 +507,8 @@ $container->setDefinitions([
$reader = $container->get('app\storage\DocumentsReader');
```
什么时候注册依赖关系 <span id="when-to-register-dependencies"></span>
-----------------------------
什么时候注册依赖关系(When to Register Dependencies) <span id="when-to-register-dependencies"></span>
------------------------------------------------
由于依赖关系在创建新对象时需要解决,因此它们的注册应该尽早完成。
如下是推荐的实践:
@ -520,8 +520,8 @@ $reader = $container->get('app\storage\DocumentsReader');
你可以将依赖关系注册到扩展的引导类中。
总结 <span id="summary"></span>
-------
总结(Summary) <span id="summary"></span>
-------------
依赖注入和[服务定位器](concept-service-locator.md)都是流行的设计模式,
它们使你可以用充分解耦且更利于测试的风格构建软件。

Loading…
Cancel
Save