Dependency Injection and IOC container in Procedural programming
A couple of funky ideas on managing dependencies in a non-object oriented application.
Dependencies management
Popular ways to manage dependencies in code are global variables, the registry pattern, service locator. These are all accessible in procedural programming, too.
Using Registry pattern with Zend Framework’s Zend_Registry class:
and this is how it’d look without objects:
Looks very similar. This is how implementation of registry\get function would look like:
However, using these approaches comes at a cost and sometimes it isn’t acceptable. What is almost always acceptable is the Dependency Injection.
Dependency Injection
The same code but using the just out of the oven Zend Framework 2(still in development) and dependency injection:
what procedural variant could look like:
As we don’t have objects in this case - the only thing we ever depend on is data. And when I say “Dependency Injection in procedural programming” I really mean data to “Data Injection”. A function may depend on data prepared in a special manner, a data structure, by passing the data through a set of functions. For instance, this is how $db could be created:
and this would be the procedural variant:
Although if you think of data structures as objects without behavior, there is no difference.
IoC Container
This is the answer for OOP, a special object whose job is to create services for you and resolve/inject all dependencies they need. Usually, you configure the container so it knows the hierarchy of objects in the app and then you get services you need from it in an upper level of your application.
The new web-framework ZF2 above already has the container built-in so you only need to configure it, with something like this:
This is very convenient, particularly because this configuration is not hardcoded in the application and you can switch configurations per environment.
Procedural IoC Container
This is my little idea for an IOC container without objects:
As we don’t have objects the container doesn’t need to create anything. Instead it should call a function on our behalf, automatically injecting dependencies (data dependencies) as function parameters. If some dependencies need to be prepared (i.e. to get some data you need to run some other functions first) - the container does that as well.
The container itself is a function, too. The first parameter is the function you want to call, the second parameter is the IOC configuration and you may provide additional parameters for the function that are known (i.e don’t need to be resolved by the container).
Here is what configuration for the container might look like, check out the comments:
And this is how you’d use it:
I could say that essentially this is currying + configuration.
Comments and feedback are much appreciated. See contact details here