Skip to end of metadata
Go to start of metadata
You are viewing an old version of this page. View the current version. Compare with Current  |   View Page History

<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[

Zend Framework: Zend_Di Component Proposal

Proposed Component Name Zend_Di
Developer Notes
Proposers My E-mail Address
Revision 0.1 - 21 November 2007: Initial Proposal.
0.2 - 29 November 2007: Added a real-life example.
0.3 - 30 November 2007: API reworked.
0.4 - 12 February 2008: API reworked. (wiki revision: 58)

Table of Contents

1. Overview

Zend_Di is a dependency injector component. It minimizes coupling between groups of classes, makes unit testing much simpler, and provides an easy way to re-configure a package to use custom implementations of components. The architecture of the Zend_Di component is based on the following concepts:

  • Dependency injection is a technique that consists of passing objects via the constructor or setter methods.
  • The Container provides an easy way of re-configuring a package to use custom implementations of components.
  • Responsibility for object management is taken over by whatever container is being used to manage those objects.

Benefits of using a DI Container:

  • Easy best practice unit testing
  • Component reuse
  • Centralized configuration
  • Clean and declarative architecture
  • Maintainability and adaptability

2. References

3. Component Requirements, Constraints, and Acceptance Criteria

  • This component will use Reflection.

4. Dependencies on Other Framework Components

  • Zend_Config (optional)
  • Zend_Exception
  • Zend_Loader

5. Theory of Operation

Zend_Di provides generic factory classes that instantiate instances of classes. These instances are then configured by the container, allowing construction logic to be reused on a broader level. For example:

Once we separate configuration from use, we can easily test the Car with different Engines. It's just a matter of re-configuring the package and injecting Zend_Car_Parts_Engine_Gas instead of Zend_Car_Parts_Engine_Fuel.

6. Milestones / Tasks

  • Milestone 1: [DONE] Design interface
  • Milestone 2: [DONE] Write proposal
  • Milestone 3: [IN PROGRESS] Gather feedback and revise design as necessary
  • Milestone 4: Review by the Zend team
  • Milestone 5: Develop full implementation and unit tests
  • Milestone 6: Documentation
  • Milestone 7: Future enhancements

7. Class Index

  • Zend_Di
  • Zend_Di_Container
  • Zend_Di_Factory
  • Zend_Di_Reflection
  • Zend_Di_Parameter
  • Zend_Di_Data
  • Zend_Di_Registry
  • Zend_Di_Storage_Interface
  • Zend_Di_Storage_Object
  • Zend_Di_Storage_Exception
  • Zend_Di_Exception

8. Use Cases

Zend_Di handles injections via the constructor or setters methods. In addition, the component allows the user to map out specifications for components and their dependencies in a configuration file and generate the objects based on that specification.

The cases below assume that the following classes have been defined:

Assembling Objects Using Reflection


Assembling Objects Using Configuration

The configuration is typically set up in a different file. Each package can have its own configuration file: PHP, INI or XML file. The configuration file holds the components specifications and package dependencies.

You can pass an instance of Zend_Config via the constructor, or set a configuration array using the setConfigArray() method.


The two major flavors of Dependency Injection are Setter Injection (injection via setter methods) and Constructor Injection (injection via constructor arguments). Zend_Di provides support for both, and even allows you to mix the two when configuring the one object.

Constructor dependency injection

When a class is loaded, the constructor method is selected by default.


Users can map out specifications for components and their dependencies. So whenever a class is loaded, Zend_Di will inject the dependencies automatically. For example:


Setter dependency injection


Zend_Di injects dependencies using the top-down fashion, starting with the constructor and ending with the setter methods.


Users can map out specifications for a component:



You can tell Zend_Di what classes to manage by adding them to a container (the order of registration has no significance). Containers can be retrieved using the Zend_Di_Container_Manager::getContainer() method, which returns an instance of Zend_Di_Container_Storage_Interface.


You can register your own container as long as you pass an instance of Zend_Di_Container_Storage_Interface. New containers can be register using the registerContainer() method.


Real-life Example

Zend_Import is a component I use to import SQL, XML and CSV files into the database. I created the Zend_Di component because:

  • I needed a way to test Zend_Import with different file formats and using different protocols.
  • I wanted to minimize coupling between the components.
  • I wanted other developers to know the components Zend_Import was using by looking at the config file or API.
  • I wanted to minimize the risk of having hidden dependencies.

The CSV files are retrieved using FTP, and the XML files using HTTP. Because the script is run by a Cron job, I also added logging capabilities to Zend_Import.

The problem I faced when designing Zend_Import was the amount of dependencies the component had: Zend_Import_Protocol, Zend_Db, Zend_Log, Zend_Log_Writer and Zend_Mail (recently added, and not included in this example). So I decided to use the dependency injection pattern to solve this problem.

Zend_Di has been tested with Zend_Import in a staging server. Below is a prototype of the Zend_Import package, and a brief example of how Zend_Import takes full advantage of the DI pattern.

Zend_Import package:

*Spec.php file:*

Prototype of the Zend_Import_Format_Csv class:


This will output:

9. Class Skeletons

  • Zend_Di_Container
  • Zend_Di_Factory
  • Zend_Di_Parameter
  • Zend_Di_Registry
  • Zend_Di_Storage_Object


Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.