Aura.Di is a dependency injection container system with the following features:
constructor and setter injection
explicit and implicit auto-resolution of typehinted constructor parameter values
configuration of setters across interfaces and traits
inheritance of constructor parameter and setter method values
lazy-loaded services, values, and instances
instance factories
We will concentrate on constructor and setter injection in this chapter for easiness. It is recommend you should read Aura.Di documentation
A “service” is an object stored in the Container under a unique name.
Any time you get()
the named service, you always get back the same object instance.
That usage is great if we want to create the Example instance at the same time we set the service. However, we generally want to create the service instance at the moment we get it, not at the moment we set it.
The technique of delaying instantiation until get()
time is called “lazy loading.” To lazy-load an instance, use the lazyNew()
method on the Container and give it the class name to be created:
Now the service is created only when we we get()
it, and not before.
This lets us set as many services as we want, but only incur the overhead of creating the instances we actually use.
When we use the Container to instantiate a new object, we often need to inject (i.e., set) constructor parameter values in various ways.
We can define default values for constructor parameters using the $di->params
array on the Container.
Let’s look at a class that takes some constructor parameters:
If we were to try to set a service using $di->lazyNew('ExampleWithParams')
,
the instantiation would fail. The $foo
param is required, and the Container
does not know what to use for that value.
To remedy this, we tell the Container what values to use for
each ExampleWithParams constructor parameter by name using the $di->params
array:
Now when a service is defined with $di->lazyNew('ExampleWithParams')
,
the instantiation will work correctly. Each time we create an
ExampleWithParams instance through the Container, it will apply
the $di->params['ExampleWithParams']
values.
If we want to override the default $di->params
values for a specific
new instance, we can pass a $params
array as the second argument to
lazyNew()
to merge with the default values. For example:
This will leave the $foo
parameter default in place, and override
the $bar
parameter value, for just that instance of the ExampleWithParams.
Sometimes a class will need another service as one of its parameters. By way of example, the following class needs a database connection:
To inject a shared service as a parameter value, use $di->lazyGet()
so that the service object is not created until the ExampleNeedsService object is created:
This keeps the service from being created until the very moment it is needed. If we never instantiate anything that needs the service, the service itself will never be instantiated.
This package supports setter injection in addition to constructor injection. (These can be combined as needed.)
After the Container constructs a new instance of an object, we can specify that certain methods should be called with certain values immediately after instantiation by using the $di->setter
array. Say we have class like the following:
We can specify that, by default, the setFoo()
method should be called with a specific value after construction like so:
The value can be any valid value: a literal, a call to lazyNew()
or lazyGet()
, and so on.
Note, however, that auto-resolution does not apply to setter methods. This is because the Container does not know which methods are setters and which are “normal use” methods.
Note also that this works only with explicitly-defined setter methods.
Setter methods that exist only via magic __call()
will not be honored.
As with constructor injection, we can note instance-specific setter
values to use in place of the defaults. We do so via the third
argument to $di->lazyNew()
. For example: