An introduction to Zend\Di – Rob Allen's DevNotes

:

Zend Framework 2 provides its own dependency injection container, Zend\Di which is a key underpinning of the entire framework and especially the MVC system. I have covered before, my thoughts on the reasons for using dependency injection, so this article looks at the fundamentals of using Zend\Di.

Constructor injection

Consider this code:

This is simple code – a UserTable must have a DatabaseAdapter. As we are using constructor injection for the dependency on DatabaseAdapter, it follows that the DatabaseAdapter object must be created first.

Standard PHP code would look like this:

As we have type-hinted the $db parameter in the constructor for UserTable, the ZendDi component can quite easily do this work for us:

This code produces exactly the same result (an instantiated $userTable) that the snippet above does, but this time, we used Zend\Di\Di to actually do the object creation.

Note that get() will always return the same object. Use newInstance() for a different one.

Parameters in dependent class constructors

If the dependent class takes constructor parameters we can use the instance manager's setParameters method. Let's assume that the DatabaseAdapter has a dsn property and looks like this:

We can set the dsn for our adapter using:

and then we get the $userTable object using this code:

We could also set the dsn property of the dependent object at the same time as we retrieve the $userTable. This is accomplished using the $parameters argument to get():

which also works as you would expect.

Setter injection

Setter injection is another popular way of setting dependencies for a class. Generally, I personally prefer to use setters for dependencies that are optional for the class to work and constructor parameters for required dependencies.

Setter injection means that we use a setXyx() method rather than the constructor, so this is how it's done with ZendDi. Lets start with the class definitions:

ZendDi understands the method format of set followed by capital letter as setter methods and we turn enable it using:

Firstly we tell the Di object that the setDatabaseAdapter() method is required in order to instantiate My\UserTable objects and then our usual call to get will work. It therefore follows that if your object has more than one set method that you want to be called by Di, then you set the required flag on all of them within the Configuration object.

Again, we get a configured UserTable object from the DI container when we call get().

Aliases

One last thing that I want to mention in this article is that Zend\Di also has the concept of aliases. These are intended to make it simpler to specify dependencies and/or substitutions. As an example, I might alias Zend\Db\Adapter\Driver\Mysqli\Mysqli to "db", allowing me to call $di->get('db') and retrieve that class. This means that I could very easily configure the container differently to alias db to a different adapter and not need to change the code that retrieves the class from the container.

Conclusion

In this article, I've tried to cover the basics of how Zend\Di works. If you want to explore more, Ralph Schindler has created a number of examples on GitHub. I recommend running them locally.

Note
I have updated the example in this article based on feedback from Ralph Schindler and Marco Pivetta.