Please note that this article is also available in French. A big thanks to Frédéric Sureau for his translation work on the English version.
Since my previous article (FR), I have kept on working on the dependencies injector of Spiral, wich I just published in a standalone version.
Here is an overview of SpiralDi functionnalities, and some examples on the use.
Table des matières
Overview
SpiralDi comes with a lot of new features, some of them inspired by the excellent Java framework : Spring. It is now possible to :
- Use factories to set the parameters values (useful for configuration)
- Use an inheritance system to make configuration file more clear
- Use factories for the construction of the services
- Directly inject the container in ContainerAware services
But, maybe, it doesn’t mean anything for you ? I will explain the details further later.
Principles
If you don’t know much about the inversion of control, I advise you to read my introduction on the dependencies injection (FR).
The use of a lightweight container is done in two steps :
- The description of the schema of all the services that will be used later
- The call (so, the construction) of these services via the container
The SpiralDi library let you describe the Schema in different ways. The sexiest is probably the XML description file, but it is also possible to define this Schema using the PHP language if you think it’s more convenient. The following examples are in XML. Here is a quite simple definition file, that describe two services :
<container>
<service name="db" class="Database">
<constructor>
<argument value="localhost"/>
<argument value="root"/>
<argument value="password"/>
</constructor>
</service>
<service name="user" class="User">
<method name="setDb">
<argument type="service" value="db"/>
</method>
</service>
</container>
Once this file is written, you have to transform it in a SpiralDi understandable format : the Schema.
$builder->setFileName("schema.xml");
$schema = $builder->buildSchema();
You can now exploit the built Schema. The Schema is first used to resolve objects. We will see later that it has much more aims. Now, pass this Schema to the Container :
$container = new SpiralDi_Container_Default($schema);
// getting the desired service
$myUser = $container->user;
This looks sexy, isn’t it ? The container has done everything ! Resolution of the object’s dependencies and injection of these dependencies when needed.
Services scope
All services constructed by SpiralDi have a controlled life time.
In the default behavior, the container will return the same instance of the object, each time the service is needed. This is the singleton scope.
All services are by default configured to have the singleton scope.
You can also use the prototype scope to make the container create a new instance each time the service is needed.
To change the scope of the service, you can use the property
in the XML file.
Advanced use
Now, you know how to describe « basic» services and their dependencies. Let’s see now, more complex features.
Using references and MethodFactory
Sometimes, you will need to inject parameters in a dynamic manner. Imagine that you don’t know the value of a parameter that you want to inject because it is stored in a configuration object for example.
So, we want the container to construct our services using information from a Config object. The container is able to generate automatically the following code for us :
$service = new Db($config->host, $config->user, $config->password);
For this, we have to use the system of references :
<constructor>
<argument ref="config" value="host"/>
<argument ref="config" value="user"/>
<argument ref="config" value="password"/>
</constructor>
</service>
It is also possible to specify the method that will be used to get arguments. For example
will produce something like this :
$service = new Db(
$config->getParam("host"),
$config->getParam("user"),
$config->getParam("password")
);
The corresponding XML code will be :
Inheriting and overloading services
Quite often, some services are similar. It is possible to use the inheritance system to make the services description lighter.
This is not an actual inheritance between classes, but only the inheritance principle. Thus, you can extend a service description, which make the description file more readable and easier to understand.
<method name="method2">
<argument value="value"/>
</method>
</service>
Container Aware
In some cases, services have to know the existence of the container, and need to access to it. It is easy to inject the container in a service by using the « container» type or the facility « containerAware» :
<!-- is exactly the same as -->
<service name="containerAwareService" class="Service">
<method name="setDiContainer">
<argument type="container" />
</method>
</service>
From the class’ point of view, you only have to implement the SpiralDi_ContainerAware interface. In this way, during the construction of the service, the setDiContainer method of your class will be automatically called.
As well, in this case, there is no need to explicitly name your service as « ContainerAware» in the description file, the container will automatically detect it
Factories
SpiralDi also provides a convenient way to use Factories from the DI. This helps generating behaviors like :
The corresponding XML code is :
<method name="createService" />
</service>
This should be nice if you want to reuse your old Singleton implementations, among other things…
<method name="getInstance" />
</service>
Download it !
Convinced ? To get the latest version of SpiralDi, you have many solutions :
Via the mercurial repository
Via the archives
The code is available in the following formats : zip, gz ou bz2
You can also directly check the repository.
That’s all ! You can now have fun using it ! For functionnality requests, bug report, etc. Please !
Interesting readings
If you want to know more about dependencies injection, here are some interesting readings on the subject :
- Martin Fowler’s article on dependencies injection
- Fabien potencier’s suite of articles (1,2,3,4,5)
- Another one from Padraic Brady (1,2)
- Fabien Potencier has also published a di container that feet in a tweet. to see, just for fun
Going further ?
SpiralDi is of course not the only PHP lightweight container. Recently, a lot of container are flowering on the web. Frameworks like Symfony and Flow31 are giving a good place to DI. So much the better !
[...] Please note that this article is also available in French . A big thanks to Frédéric Sureau for his translation work on the English version. Since my previous article (FR) , I have kept on working on the dependencies injector of Spiral , wich I just published in a standalone version Original post: Dependency Injection – Using SpiralDi Container [...]
Dependency Injection – Using SpiralDi Container | Adobe Tutorials
23 juin 09 at 2:19
Moi j’aime pas Frédéric Sureau. En plus il a un nom d’arbuste.
Quentin
3 déc 09 at 1:01