Thursday, October 23, 2008

Zend_Container Thoughts

See Zend_Container Thoughts at its new home on bradley-holt.com.

It seems that there's some interest in my Zend_Container proposal including possibly using it as part of Zend_Application. I still need to move Zend_Container from "New" to "Ready for Review" but first I need to add some more details to the proposal. I want to talk about some thoughts on Zend_Container that may be helpful in understanding how it could be useful. For those who aren't familiar with it, Zend_Container is a proposal for a simple dependency injection container in Zend Framework.

I have been asked to show some more use cases for Zend_Container. I think the main thing that people want to see (correct me if I'm wrong) is how Zend_Container would be used as part of a larger web application. In order for Zend_Container to work, it needs to "contain" all of the components that it will be responsible for managing. This means that every component that will either a) be a dependency for other components or b) have a dependency on other components (or both) needs to get added to the container.

In the proposal I show an example of the getComponent method as a way to get instances out of the container. However, use of this method is discouraged. You should instead use setter injection (I'm not sure yet if the proposal will support constructor injection) and let the container provide the instance for you. Dependency injection is sometimes referred to as "inversion of control (IoC)" because it requires you to invert your thinking. In your individual components you are giving control over to the container and letting it provide your dependencies for you rather than reaching out and fulfilling these dependencies yourself (as is done currently with Zend_Registry). This is why every component needs to be added to the container — how else would the container know what to inject or even be able to perform this injection?

This inevitably leads to the question, how do we bootstrap all of this? In other words, how do we get all of these components into the container in the first place so all of this "magic" can happen? In the proposal, I showed examples of manually adding components using the addComponent method. This is a great way to add components and there is nothing wrong with doing this. However, this could start to become impractical if you have a lot of components to add to the container. Another option is to use configuration to add all of the components. I don't have an example of this yet in the proposal, but the basic idea is to list a bunch of components in your configuration and let Zend_Container add all of the components based on this information. This is more practical when you have a lot of components to add to the container.

Another option, which is not yet in the proposal, is to use a combination of directory/file scanning and reflection to add components. This could be hugely beneficial to modular applications - simply drop in your module directory and Zend_Container could automatically load components from your module. This is the sort of thing that I think the people working on Zend_Application thought might be helpful (let me know if I'm way off-base here). Of course, this opens up a host of potential efficiency issues that would need to be thought through (i.e. components should probably be "lazily" loaded and implementation/interface mappings maybe should be cached).

While I haven't yet provided any more use cases, I hope this information is helpful in understanding the role Zend_Container could play within Zend Framework. As always, I'm open to feedback even though the proposal isn't officially "Ready for Review." So far I've mainly focused on the "pure" dependency injection parts of the proposal so any other ideas on how Zend_Container could be used as part of a larger application would be great.

1 comment:

Steve said...

I'd like to see Zend_Container become a reality for the awesome ability it gives to properly unit test various parts of an app. Inject mock objects into all the dependencies and go to town.