Commit 135b944c by Qiang Xue

Finished guide about DI container and service locator.

parent 4e5079ab
Service Locator Service Locator
=============== ===============
> Note: This chapter needs cleanup.
Both service locator and dependency injection are popular design patterns that allow building software
in a loosely-coupled fashion. Yii uses service locator and dependency injection extensively,
even though you may not be aware of them. In this tutorial, we will explore their implementation
and support to help you write code more consciously. We also highly recommend you to read
[Martin's article](http://martinfowler.com/articles/injection.html) to get a deeper understanding of
service locator and dependency injection.
A service locator is an object that knows how to provide all sorts of services (or components) that an application A service locator is an object that knows how to provide all sorts of services (or components) that an application
might need. Within a service locator, each component has only a single instance which is uniquely identified by an ID. might need. Within a service locator, each component has only a single instance which is uniquely identified by an ID.
You use the ID to retrieve a component from the service locator. In Yii, a service locator is simply an instance You use the ID to retrieve a component from the service locator.
of [[yii\di\ServiceLocator]] or its child class.
In Yii, a service locator is simply an instance of [[yii\di\ServiceLocator]] or its child class.
The most commonly used service locator in Yii is the *application* object which can be accessed through The most commonly used service locator in Yii is the *application* object which can be accessed through
`\Yii::$app`. The services it provides are called *application components*, such as `request`, `response`, `\Yii::$app`. The services it provides are called *application components*, such as the `request`, `response`,
`urlManager`. You may configure these components or replace them with your own implementations easily `urlManager` components. You may configure these components or even replace them with your own implementations easily
through functionality provided the service locator. through functionality provided the service locator.
Besides the application object, each module object is also a service locator. Besides the application object, each module object is also a service locator.
...@@ -26,7 +18,10 @@ To use a service locator, the first step is to register components. A component ...@@ -26,7 +18,10 @@ To use a service locator, the first step is to register components. A component
via [[yii\di\ServiceLocator::set()]]. The following code shows different ways of registering components: via [[yii\di\ServiceLocator::set()]]. The following code shows different ways of registering components:
```php ```php
$locator = new \yii\di\ServiceLocator; use yii\di\ServiceLocator;
use yii\caching\FileCache;
$locator = new ServiceLocator;
// register "cache" using a class name that can be used to create a component // register "cache" using a class name that can be used to create a component
$locator->set('cache', 'yii\caching\ApcCache'); $locator->set('cache', 'yii\caching\ApcCache');
...@@ -43,6 +38,9 @@ $locator->set('db', [ ...@@ -43,6 +38,9 @@ $locator->set('db', [
$locator->set('search', function () { $locator->set('search', function () {
return new app\components\SolrService; return new app\components\SolrService;
}); });
// register "pageCache" using a component
$locator->set('pageCache', new FileCache);
``` ```
Once a component is registered, you can access it using its ID in one of the following two ways: Once a component is registered, you can access it using its ID in one of the following two ways:
...@@ -62,11 +60,10 @@ You may use [[yii\di\ServiceLocator::has()]] to check if a component ID has alre ...@@ -62,11 +60,10 @@ You may use [[yii\di\ServiceLocator::has()]] to check if a component ID has alre
If you call [[yii\di\ServiceLocator::get()]] with an invalid ID, an exception will be thrown. If you call [[yii\di\ServiceLocator::get()]] with an invalid ID, an exception will be thrown.
Because service locators are often being configured using configuration arrays, a method named Because service locators are often being created with [configurations](concept-configurations.md),
[[yii\di\ServiceLocator::setComponents()]] is provided to allow registering components in configuration arrays. a writable property named [[yii\di\ServiceLocator::setComponents()|components]] is provided so that
The method is a setter which defines a writable property `components` that can be configured. you can configure it and register multiple components at once. The following code shows a configuration array
The following code shows a configuration array that can be used to configure an application and register that can be used to configure an application and register the "db", "cache" and "search" components:
the "db", "cache" and "search" components:
```php ```php
return [ return [
......
...@@ -36,6 +36,8 @@ class ContainerTest extends TestCase ...@@ -36,6 +36,8 @@ class ContainerTest extends TestCase
$this->assertTrue($foo instanceof $Foo); $this->assertTrue($foo instanceof $Foo);
$this->assertTrue($foo->bar instanceof $Bar); $this->assertTrue($foo->bar instanceof $Bar);
$this->assertTrue($foo->bar->qux instanceof $Qux); $this->assertTrue($foo->bar->qux instanceof $Qux);
$foo2 = $container->get($Foo);
$this->assertFalse($foo === $foo2);
// full wiring // full wiring
$container = new Container; $container = new Container;
...@@ -80,5 +82,12 @@ class ContainerTest extends TestCase ...@@ -80,5 +82,12 @@ class ContainerTest extends TestCase
$this->assertTrue($foo instanceof $Foo); $this->assertTrue($foo instanceof $Foo);
$this->assertTrue($foo->bar instanceof $Bar); $this->assertTrue($foo->bar instanceof $Bar);
$this->assertTrue($foo->bar->qux instanceof $Qux); $this->assertTrue($foo->bar->qux instanceof $Qux);
// wiring by closure
$container = new Container;
$container->set('qux', new Qux);
$qux1 = $container->get('qux');
$qux2 = $container->get('qux');
$this->assertTrue($qux1 === $qux2);
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment