Version 7 by Maks 3w
on Aug 18, 2012 09:38.

compared with
Current by Dolf Schimmel (Freeaqingme)
on Dec 13, 2013 21:51.

Key
This line was removed.
This word was removed. This word was added.
This line was added.

Changes (154)

View Page History
{toc:maxLevel=3}
h1. Please refer to the main ZF2 documentation to get an updated version of this QuickStart: http://zf2.readthedocs.org/en/latest/modules/zend.di.quick-start.html

{warning=Outdated}
Please refer to the main ZF2 documentation to get an updated version of this QuickStart http://zf2.readthedocs.org/en/latest/modules/zend.di.quick-start.html
{warning}
<ac:macro ac:name="toc"><ac:parameter ac:name="maxLevel">3</ac:parameter></ac:macro>

{info=Available since 2.0.0dev3}
Please note that the DI component has only been available starting in 2.0.0dev3 and forward. Also, please note that the component is still under review, and the API and functionality offered may change before the first beta release.
{info}
<ac:macro ac:name="warning"><ac:parameter ac:name="title">Outdated</ac:parameter><ac:rich-text-body>
<p>Please refer to the main ZF2 documentation to get an updated version of this QuickStart <a class="external-link" href="http://zf2.readthedocs.org/en/latest/modules/zend.di.quick-start.html">http://zf2.readthedocs.org/en/latest/modules/zend.di.quick-start.html</a></p></ac:rich-text-body></ac:macro>

h2. A Very Brief Introduction to DI
<ac:macro ac:name="info"><ac:parameter ac:name="title">Available since 2.0.0dev3</ac:parameter><ac:rich-text-body>
<p>Please note that the DI component has only been available starting in 2.0.0dev3 and forward. Also, please note that the component is still under review, and the API and functionality offered may change before the first beta release.</p></ac:rich-text-body></ac:macro>

_Dependency Injection_ is a concept that has been talked about in numerous places over the web. For the purposes of this quickstart, we'll explain the act of injecting dependencies simply with this below code:
<h2>A Very Brief Introduction to DI</h2>

<p><em>Dependency Injection</em> is a concept that has been talked about in numerous places over the web. For the purposes of this quickstart, we'll explain the act of injecting dependencies simply with this below code:</p>
{code:php}
<ac:macro ac:name="code"><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[
$b = new B(new A));
{code}
]]></ac:plain-text-body></ac:macro>

Above, A is a dependency of B, and A was _injected_ into B. If you are not familar with the concept of dependency injection, here are a couple of great reads: Matthew Weier O'Phinney's [Analogy|http://weierophinney.net/matthew/archives/260-Dependency-Injection-An-analogy.html], Ralph Schindler's [Learning DI|http://ralphschindler.com/2011/05/18/learning-about-dependency-injection-and-php], or Fabien Potencier's [Series on DI|http://fabien.potencier.org/article/11/what-is-dependency-injection].
<p>Above, A is a dependency of B, and A was <em>injected</em> into B. If you are not familar with the concept of dependency injection, here are a couple of great reads: Matthew Weier O'Phinney's <a href="http://weierophinney.net/matthew/archives/260-Dependency-Injection-An-analogy.html">Analogy</a>, Ralph Schindler's <a href="http://ralphschindler.com/2011/05/18/learning-about-dependency-injection-and-php">Learning DI</a>, or Fabien Potencier's <a href="http://fabien.potencier.org/article/11/what-is-dependency-injection">Series on DI</a>. </p>

h2. A Very Brief Introduction to DI Containers
<h2>A Very Brief Introduction to DI Containers</h2>

<p>TBD</p>

h2. Simplest Usage Case (2 classes, one consumes the other)
<h2>Simplest Usage Case (2 classes, one consumes the other)</h2>

In the simplest use case, a developer might have one class ({{A}}) that is consumed by another class ({{B}}) through the constructor. By having the dependency injected through the constructor, this requires an object of type {{A}} be instantiated before an object of type {{B}} so that {{A}} can be injected into {{B}}.
<p>In the simplest use case, a developer might have one class (<code>A</code>) that is consumed by another class (<code>B</code>) through the constructor. By having the dependency injected through the constructor, this requires an object of type <code>A</code> be instantiated before an object of type <code>B</code> so that <code>A</code> can be injected into <code>B</code>.</p>

{code:php}
<ac:macro ac:name="code"><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[
namespace My
{
}
}
{code}
]]></ac:plain-text-body></ac:macro>

<p>To create {{B}} <code>B</code> by hand, a developer would follow this work flow, or a similar workflow to this:</p>

{code:php}
<ac:macro ac:name="code"><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[
$b = new B(new A());
{code}
]]></ac:plain-text-body></ac:macro>

<p>If this workflow becomes repeated throughout your application multiple times, this creates an opportunity where one might want to DRY up the code. While there are several ways to do this, using a dependency injection container is one of these solutions. With ZF's dependency injection container {{Zend\Di\DependencyInjector}}, <code>Zend\Di\DependencyInjector</code>, the above use case can be taken care of with no configuration (provided all of your autoloading is already configured properly) with the following usage: </p>

{code:php}
<ac:macro ac:name="code"><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[
$di = new Zend\Di\DependencyInjector;
$b = $di->get('My\B'); // will produce a B object that is consuming an A object
{code}
]]></ac:plain-text-body></ac:macro>

<p>Moreover, by using the {{DependencyInjector::get()}} <code>DependencyInjector::get()</code> method, you are ensuring that the same exact object is returned on subsequent calls. To force new objects to be created on each and every request, one would use the {{DependencyInjector::newInstance()}} method: <code>DependencyInjector::newInstance()</code> method:</p>

{code:php}
<ac:macro ac:name="code"><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[
$b = $di->newInstance('My\B');
{code}
]]></ac:plain-text-body></ac:macro>

<p>Let's assume for a moment that {{A}} <code>A</code> requires some configuration before it can be created. Our previous use case is expanded to this (we'll throw a 3rd class in for good measure): </p>

{code:php}
<ac:macro ac:name="code"><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[
namespace My
{
}
}
{code}
]]></ac:plain-text-body></ac:macro>

<p>With the above, we need to ensure that our {{DependencyInjector}} <code>DependencyInjector</code> is capable of seeing the {{A}} <code>A</code> class with a few configuration values (which are generally scalar in nature). To do this, we need to interact with the {{InstanceManager}}: <code>InstanceManager</code>:</p>

{code:php}
<ac:macro ac:name="code"><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[
$di = new Zend\Di\DependencyInjector;
$di->getInstanceManager()->setParameters('A', array(
'password' => 'MyHardToGuessPassword%$#'
);
{code}
]]></ac:plain-text-body></ac:macro>

Now that our container has values it can use when creating {{A}}, and our new goal is to have a {{C}} object that consumes {{B}} and in turn consumes {{A}}, the usage scenario is still the same:
<p>Now that our container has values it can use when creating <code>A</code>, and our new goal is to have a <code>C</code> object that consumes <code>B</code> and in turn consumes <code>A</code>, the usage scenario is still the same:</p>

{code:php}
<ac:macro ac:name="code"><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[
$c = $di->get('My\C');
// or
$c = $di->newInstance('My\C');
{code}
]]></ac:plain-text-body></ac:macro>

Simple enough, but what if we wanted to pass in these parameters at call time? Assuming a default {{DependencyInjector}} object ({{$di = new Zend\Di\DependencyInjector()}} without any configuration to the {{InstanceManager}}), we could do the following:
<p>Simple enough, but what if we wanted to pass in these parameters at call time? Assuming a default <code>DependencyInjector</code> object (<code>$di = new Zend\Di\DependencyInjector()</code> without any configuration to the <code>InstanceManager</code>), we could do the following:</p>

{code:php}
<ac:macro ac:name="code"><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[
$parameters = array(
'username' => 'MyUsernameValue',
// or
$c = $di->newInstance('My\C', $parameters);
{code}
]]></ac:plain-text-body></ac:macro>

<p>Constructor injection is not the only supported type of injection. The other most popular method of injection is also supported: setter injection. Setter injection allows one to have a usage scenario that is the same as our previous example with the exception, for example, of our {{B}} <code>B</code> class now looking like this:</p>

{code:php}
<ac:macro ac:name="code"><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[
namespace My
{
}
}
{code}
]]></ac:plain-text-body></ac:macro>

<p>Since the method is prefixed with set, and is followed by a capital letter, the {{DependencyInjector}} <code>DependencyInjector</code> knows that this method is used for setter injection, and again, the use case {{$c <code>$c = $di-&gt;get('C')}}, $di-&gt;get('C')</code>, will once again know how to fill the dependencies when needed to create an object of type {{C}}. <code>C</code>.</p>

<p>Other methods are being created to determine what the wirings between classes are, such as interface injection and annotation based injection.</p>

h2. Simplest Usage Case Without Type-Hints
<h2>Simplest Usage Case Without Type-Hints</h2>

<p>If your code does not have type-hints or you are using 3rd party code that does not have type-hints but does practice dependency injection, you can still use the {{DependencyInjector}}, <code>DependencyInjector</code>, but you might find you need to describe your dependencies explicitly. To do this, you will need to interact with one of the definitions that is capable of letting a developer describe, with objects, the map between classes. This particular definition is called the {{BuilderDefinition}} <code>BuilderDefinition</code> and can work with, or in place of, the default {{RuntimeDefinition}}. <code>RuntimeDefinition</code>.</p>

Definitions are a part of the {{DependencyInjector}} that attempt to describe the relationship between classes so that {{DependencyInjector::newInstance()}} and {{DependencyInjector::get()}} can know what the dependencies are that need to be filled for a particular class/object. With no configuration, {{DependencyInjector}} will use the {{RuntimeDefinition}} which uses reflection and the type-hints in your code to determine the dependency map. Without type-hints, it will assume that all dependencies are scalar or required configuration parameters.
<p>Definitions are a part of the <code>DependencyInjector</code> that attempt to describe the relationship between classes so that <code>DependencyInjector::newInstance()</code> and <code>DependencyInjector::get()</code> can know what the dependencies are that need to be filled for a particular class/object. With no configuration, <code>DependencyInjector</code> will use the <code>RuntimeDefinition</code> which uses reflection and the type-hints in your code to determine the dependency map. Without type-hints, it will assume that all dependencies are scalar or required configuration parameters.</p>

The {{BuilderDefinition}}, which can be used in tandem with the {{RuntimeDefinition}} (technically, it can be used in tandem with any definition by way of the {{AggregateDefinition}}), allows you to programmatically describe the mappings with objects. Let's say for example, our above {{A/B/C}} usage scenario, were altered such that class {{B}} now looks like this:
<p>The <code>BuilderDefinition</code>, which can be used in tandem with the <code>RuntimeDefinition</code> (technically, it can be used in tandem with any definition by way of the <code>AggregateDefinition</code>), allows you to programmatically describe the mappings with objects. Let's say for example, our above <code>A/B/C</code> usage scenario, were altered such that class <code>B</code> now looks like this: </p>

{code:php}
<ac:macro ac:name="code"><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[
namespace My
{
}
}
{code}
]]></ac:plain-text-body></ac:macro>

<p>You'll notice the only change is that setA now does not include any type-hinting information.</p>

{code:php}
<ac:macro ac:name="code"><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[
use Zend\Di\DependencyInjector,
Zend\Di\Definition,

$c = $di->get('My\C', $parameters);
{code}
]]></ac:plain-text-body></ac:macro>

<p>This above usage scenario provides that whatever the code looks like, you can ensure that it works with the dependency injection container. In an ideal world, all of your code would have the proper type hinting and/or would be using a mapping strategy that reduces the amount of bootstrapping work that needs to be done in order to have a full definition that is capable of instantiating all of the objects you might require.</p>

h2. Simplest Usage Case With Compiled Definitions
<h2>Simplest Usage Case With Compiled Definitions</h2>

<p>Without going into the gritty details, as you might expect, PHP at its core is not DI friendly. Out-of-the-box, the {{DependencyInjector}} <code>DependencyInjector</code> uses a {{RuntimeDefinition}} <code>RuntimeDefinition</code> which does all class map resolution via PHP's {{Reflection}} <code>Reflection</code> extension. Couple that with the fact that PHP does not have a true application layer capable of storing objects in-memory between requests, and you get a recipe that is less performant than similar solutions you'll find in Java and .Net (where there is an application layer with in-memory object storage.)</p>

<p>To mitigate this shortcoming, {{Zend\Di}} <code>Zend\Di</code> has several features built in capable of pre-compiling the most expensive tasks that surround dependency injection. It is worth noting that the {{RuntimeDefition}}, <code>RuntimeDefition</code>, which is used by default, is the *only* <strong>only</strong> definition that does lookups on-demand. The rest of the {{Definition}} <code>Definition</code> objects are capable of being aggregated and stored to disk in a very performant way.</p>

<p>Ideally, 3rd party code will ship with a pre-compiled {{Definition}} <code>Definition</code> that will describe the various relationships and parameter/property needs of each class that is to be instantiated. This {{Definition}} <code>Definition</code> would have been built as part of some deployment or packaging task by this 3rd party. When this is not the case, you can create these {{Definitions}} <code>Definitions</code> via any of the {{Definition}} <code>Definition</code> types provided with the exception of the {{RuntimeDefinition}}. <code>RuntimeDefinition</code>. Here is a breakdown of the job of each definition type:</p>

<ul>
* {{AggregateDefinition}} <li><code>AggregateDefinition</code> - Aggregates multiple definitions of various types. When looking for a class, it looks it up in the order the definitions were provided to this aggregate.</li>
* {{ArrayDefinition}} - This definition takes an array of information and exposes it via the interface provided by {{Zend\Di\Definition}} suitable for usage by {{DependencyInjector}} or an {{AggregateDefinition}}
* {{BuilderDefinition}} - Creates a definition based on an object graph consisting of various {{Builder\PhpClass}} objects and {{Builder\InectionMethod}} objects that describe the mapping needs of the target codebase and …
* {{Compiler}} - This is not actually a definition, but produces an {{ArrayDefinition}} based off of a code scanner ({{Zend\Code\Scanner\DirectoryScanner}} or {{Zend\Code\Scanner\FileScanner}}).
<li><code>ArrayDefinition</code> - This definition takes an array of information and exposes it via the interface provided by <code>Zend\Di\Definition</code> suitable for usage by <code>DependencyInjector</code> or an <code>AggregateDefinition</code></li>
<li><code>BuilderDefinition</code> - Creates a definition based on an object graph consisting of various <code>Builder\PhpClass</code> objects and <code>Builder\InectionMethod</code> objects that describe the mapping needs of the target codebase and &hellip;</li>
<li><code>Compiler</code> - This is not actually a definition, but produces an <code>ArrayDefinition</code> based off of a code scanner (<code>Zend\Code\Scanner\DirectoryScanner</code> or <code>Zend\Code\Scanner\FileScanner</code>).</li>
</ul>

The following is an example of producing a definition via a {{DirectoryScanner}}:

<p>The following is an example of producing a definition via a <code>DirectoryScanner</code>:</p>
{code:php}
<ac:macro ac:name="code"><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[
$compiler = new Zend\Di\Definition\Compiler();
$compiler->addCodeScannerDirectory(
);
$definition = $compiler->compile();
{code}
]]></ac:plain-text-body></ac:macro>

This definition can then be directly used by the {{DependencyInjector}} (assuming the above {{A, B, C}} scenario was actually a file per class on disk):
<p>This definition can then be directly used by the <code>DependencyInjector</code> (assuming the above <code>A, B, C</code> scenario was actually a file per class on disk):</p>

{code:php}
<ac:macro ac:name="code"><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[
$di = new Zend\Di\DependencyInjector;
$di->setDefinition($definition);
$di->getInstanceManager()->setParameters('My\A', array('username' => 'foo', 'password' => 'bar'));
$c = $di->get('My\C');
{code}
]]></ac:plain-text-body></ac:macro>

<p>One strategy for persisting these compiled definitions would be the following:</p>

{code:php}
<ac:macro ac:name="code"><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[
if (!file_exists(__DIR__ . '/di-definition.php') &amp;&amp; $isProduction) {
$compiler = new Zend\Di\Definition\Compiler();
// $definition can now be used; in a production system it will be written
// to disk.
{code}
]]></ac:plain-text-body></ac:macro>

Since {{Zend\Code\Scanner}} <p>Since <code>Zend\Code\Scanner</code> does not include files, the classes contained within are not loaded into memory. Instead, {{Zend\Code\Scanner}} <code>Zend\Code\Scanner</code> uses tokenization to determine the structure of your files. This makes this suitable to use this solution during development and within the same request as any one of your application's dispatched actions.</p>

h2. Creating A Precompiled Definition For Others To Use
<h2>Creating A Precompiled Definition For Others To Use</h2>

If you are a 3rd party code developer, it makes sense to produce a {{Definition}} file that describes your code so that others can utilize this {{Definition}} without having to {{Reflect}} it via the {{RuntimeDefintion}}, or create it via the {{Compiler}}. To do this, use the same technique as above. Instead of writing the resulting array to disk, you would write the information into a definition directly, by way of {{Zend\CodeGenerator}}:
<p>If you are a 3rd party code developer, it makes sense to produce a <code>Definition</code> file that describes your code so that others can utilize this <code>Definition</code> without having to <code>Reflect</code> it via the <code>RuntimeDefintion</code>, or create it via the <code>Compiler</code>. To do this, use the same technique as above. Instead of writing the resulting array to disk, you would write the information into a definition directly, by way of <code>Zend\CodeGenerator</code>:</p>

{code:php}
<ac:macro ac:name="code"><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[
// First, compile the information
$compiler = new Zend\Di\Definition\Compiler();
));
file_put_contents(__DIR__ . '/My/DiDefinition.php', $codeGenerator->generate());
{code}
]]></ac:plain-text-body></ac:macro>

h2. Using Multiple Definitions From Multiple Sources
<h2>Using Multiple Definitions From Multiple Sources</h2>

<p>In all actuality, you will be using code from multiple places, some Zend Framework code, some other 3rd party code, and of course, your own code that makes up your application. Here is a method for consuming definitions from multiple places:</p>

{code:php}
<ac:macro ac:name="code"><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[
use Zend\Di\DependencyInjector,
Zend\Di\Definition,
}

{code}
]]></ac:plain-text-body></ac:macro>

h2. Generating Service Locators
<h2>Generating Service Locators</h2>

<p>In production, you want things to be as fast as possible. The Dependency Injection Container, while engineered for speed, still must do a fair bit of work resolving parameters and dependencies at runtime. What if you could speed things up and remove those lookups?</p>

The {{Zend\Di\ServiceLocator\Generator}} <p>The <code>Zend\Di\ServiceLocator\Generator</code> component can do just that. It takes a configured DI instance, and generates a service locator class for you from it. That class will manage instances for you, as well as provide hard-coded, lazy-loading instantiation of instances.</p>

<p>The method {{getCodeGenerator()}} <code>getCodeGenerator()</code> returns an instance of {{Zend\CodeGenerator\Php\PhpFile}}, <code>Zend\CodeGenerator\Php\PhpFile</code>, from which you can then write a class file with the new Service Locator. Methods on the {{Generator}} <code>Generator</code> class allow you to specify the namespace and class for the generated Service Locator.</p>

As an example, consider the following:
<p>As an example, consider the following:</p>

{code:php}
<ac:macro ac:name="code"><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[
use Zend\Di\ServiceLocator\Generator;

$file->setFilename(__DIR__ . '/../Application/Context.php');
$file->write();
{code}
]]></ac:plain-text-body></ac:macro>

The above code will write to {{../Application/Context.php}}, and that file will contain the class {{Application\Context}}. That file might look like the following:
<p>The above code will write to <code>../Application/Context.php</code>, and that file will contain the class <code>Application\Context</code>. That file might look like the following:</p>

{code:php}
<ac:macro ac:name="code"><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[
<?php

}
}
{code}
]]></ac:plain-text-body></ac:macro>

<p>To use this class, you simply consume it as you would a DI container:</p>

{code:php}
<ac:macro ac:name="code"><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[
$container = new Application\Context;

$struct = $container->get('struct'); // My\Struct instance
{code}
]]></ac:plain-text-body></ac:macro>

<p>One note about this functionality in its current incarnation. Configuration is per-environment only at this time. This means that you will need to generate a container per execution environment. Our recommendation is that you do so, and then in your environment, specify the container class to use. </p> objects that describe the mapping needs of the target codebase and , from which you can then write a class file with the new Service Locator. Methods on the