ZF2 Dependency Injection: Managing Configuration – Part 1

Configuration is a big reason to use a Dependency Injection Container (DiC).  I’ve been doing a lot of playing around with the ZF2 DiC and one of the things that I like about it is the ability to retrieve fully configured objects in  one line of code.  I’ve been going a bit overboard lately but there’s a lot of stuff you can do that can just be downright complex to handle on your own, all the time.

In my previous blog post I showed how you could provide parameters to object that you’re pulling from a DiC and have them populated in the resulting object.  As cool as that is, it’s not a massive saving as you need to manually inject the parameters into the DiC.  You can often do the same thing by setting up the DiC ahead of time to get the object with those parameters pre-set.

Let’s start by defining a class.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Test
{
  protected $test;
 
  public function __construct($test)
  {
    $this->test = $test;
  }
 
  public function getTest()
  {
    return $this->test;
  }
}

What we did before was use call time parameters to set the $test variable.

1
2
3
$di = new Di();
$test = $di->get('Test', array('test' => 'some data'));
echo $test->getTest();

Running this produces

1
'some data'

What if we either don’t know what ‘test’ will be, we want to minimize our code or we want to centralize our injection requirements?  For any of those we can set up the DiC to inject that data for us.

1
2
3
4
5
6
7
8
9
$config = array(
  'instance' => array(
    'Test' => array( // Class name
      'parameters' => array(
        'test' => 'some data'
      )
    )
  )
);

The structure of the configuration is this.  The first level is the key “instance”.  This will limit the objects created to a single instance in the DiC when requested with given set of parameters, similar to a registry (someone in the ZF team can correct me if I’m wrong).  The second level of the array is the key of the class name.  Our class is called “Test” and so we call the key “Test”.  If it was “Api\Service\Account” the key would be “Api\Service\Account”.  Next up are various options for the injection.  The only option I’m concerned with is the “parameters” one.  That is where you put in the various injections the object needs in a key/value array.

In the parameters array the keys will refer to the names of the variables you are injecting into the class.  The DiC will try to match it in two places.  The first is the named parameters in the constructor and the second are the variable names in the setters in the class.  The latter scenario may require some additional information, but we’ll look at that in a later blog post.

The first thing we need to do is take that configuration and provide it to a configuration object and then have the configuration object configure the DiC for us.

1
2
3
4
5
use Zend\Di\Configuration;
 
$diConfig = new Configuration($config);
$di = new Di();
$diConfig->configure($di);

We now have a configured DI object.  So to execute our code from earlier we change it just slightly.

1
2
$test = $di->get('Test');
echo $test->getTest();

The could echos

1
'some data'

This is now equivalent to our previous call.  Now this may seem all nice and well, but there’s more to it.  What if your object depends on an instance of another class.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Test
{
  protected $test;
 
  public function __construct(Exam $test)
  {
    $this->test = $test;
  }
 
  public function getTest()
  {
    return $this->test;
  }
}
 
class Exam
{
  protected $grade;
 
  public function __construct($grade)
  {
    $this->grade = $grade;
  }
 
  public function getGrade()
  {
    return $this->grade;
  }
}

We have two classes.  One called Test and one called Exam.  Test requires Exam and so we need to define that injection requirement.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$config = array(
  'instance' => array(
    'Test' => array( // Class name
      'parameters' => array(
        'test' => 'Exam'
      )
    ),
    'Exam' => array(
      'parameters' => array(
        'grade' => 'A+'
      )
    )
  )
);

We redefined our Test injection to require an instance of “Exam” and we added another instance definition for Exam which provides the grade.  Then we’ll change our code slightly.

1
2
3
$test = $di->get('Test');
echo get_class($test->getTest()) . "\n";
echo $test->getTest()->getGrade();

And when we run it we get

1
2
Exam
A+

With that you can now configure a DI Container and start providing references to various objects in and around your application.

There is more to talk about but we’ll leave this post at that.  Check back soon for more examples.

0 comments

Trackbacks

  1. […] Schroeder has a new post talking about dependency injection in a Zend Framework v2-based application and managing your configurations. In my previous blog post I showed how you could provide […]

  2. […] Configuration is a big reason to use a Dependency Injection Container (DiC). I’ve been doing a lot of playing around with the ZF2 DiC and one of the things that I like about it is the ability to retrieve fully configured objects in one line of code. I’ve been going a bit overboard lately but there’s a lot of stuff you can do that can just be downright complex to handle on your own, all the time. Zend 2 Article […]

Post Navigation

Web Analytics