Tag Archives: Dependency-injection

Handling ZF2 FQ Dependency Setter Injections

In a previous article I showed how you could pass in a fully qualified parameter name into the Dependency Injection Container (DiC) if you needed to be specific about where you need to have something injected.  There is an alternate method here that is cleaner than what I did before.  Let’s start with a Test class.

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

The way I did it in the previous example was by defining the fully qualified parameter name by doing this.

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

Which is fine until you you have

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

It can get a little convoluted, plus I’m not entirely convinced that’s the best way of doing it.  Parameters seem to be more useful for doing constructor injection.  A better method for setters seems to be through the use of injectors.  Let’s take at an injector configuration.

1
2
3
4
5
6
7
8
9
10
11
$config = array(
  'instance' => array(
    'Test' => array( // Class name
      'injections' => array(
        'setTest' => array(
          array('test' => 'somedata')
        )
      )
    )
  )
);

Basically, rather an using the “parameter” key use “injections” and specify an array of injection methods.  Each of those methods needs an associative array of parameter names as the key with the values as the value.  Injectors seem to be much nicer and cleaner than my previous way of doing the fully qualified parameter.

ZF2 Dependency Injection – Multiple Object Instances

When you work with the ZF2 Dependency Injection Container (DiC) when you make multiple requests for an instance of an object you will get the same object back each time.

For example, with this code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Test
{
  protected $test;
 
  public function __construct($test)
  {
    $this->test = $test;
  }
 
  public function getTest()
  {
    return $this->test;
  }
}
 
use Zend\Di\Di;
$di = new Di();
 
$test = $di->get('Test', array('test' => 'some data'));
var_dump($test);
$test2 = $di->get('Test', array('test' => 'some data'));
var_dump($test2);

You will get the following output

1
2
3
4
5
6
7
8
object(Test)#9 (1) {
["test":protected]=>
string(9) "some data"
}
object(Test)#9 (1) {
["test":protected]=>
string(9) "some data"
}

If you provide a different parameter you will get a different object.

1
2
3
4
$test = $di->get('Test', array('test' => 'some data'));
var_dump($test);
$test2 = $di->get('Test', array('test' => 'some other data'));
var_dump($test2);

Produces

1
2
3
4
5
6
7
8
object(Test)#9 (1) {
["test":protected]=>
string(9) "some data"
}
object(Test)#11 (1) {
["test":protected]=>
string(15) "some other data"
}

From this we can conclude that when you are using the DiC that if you request a like object with like parameters you will get the same instance of the object.

But what if you want the injection benefits of the DiC but don’t want to share the object?  Use the DiC’s newInstance method instead with the third parameter being false.  This tells the DiC container to refrain from putting it in the shared object pool.  The get() method does not give you the option of retrieving a non-shared instance and so you will need to call the newInstance() method directly.

1
2
3
4
5
$test = $di->get('Test', array('test' => 'some data'));
var_dump($test);
 
$test2 = $di->newInstance('Test', array('test' => 'some data'), false);
var_dump($test2);

prints out

1
2
3
4
5
6
7
8
object(Test)#9 (1) {
["test":protected]=>
string(9) "some data"
}
object(Test)#11 (1) {
["test":protected]=>
string(9) "some data"
}

 

ZF2 Dependency Injection: Managing Configuration – Part 2

In my previous post about Dependency Injection Container (DiC) configuration I made mention of some more complicated scenarios that you can use to configure your objects.  Not that you need help to make it  more complicated.  One of the things I have observed is that the more familiar I am with the DiC the more complicated the configuration gets.  This is both good and bad.  It’s good because you start understanding how and why all of those frigging long example DI configuration arrays are like that.  The bad is that  long DiC configuration arrays greatly reduce the ability of a new developer to start being productive.  That’s why I think this series of blog posts are good.  They show you how to get started small which is really the only way to get started if you aren’t intimately familiar with a DiC.

Let’s take our Test class and change its behavior by adding a method that allows you to set some test data (use your imagination here before complaining in the comments that it’s not a real world example).

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
class Test
  {
  protected $test;
  protected $data;
 
  public function setTestData($test)
  {
    $this->data = $test;
  }
 
  public function getTestData()
  {
    return $this->data;
  }
 
  public function setTest($test)
  {
    $this->test = $test;
  }
 
  public function getTest()
  {
    return $this->test;
  }
}

We dutifully set up our DiC

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$config = array(
  'instance' => array(
    'Test' => array( // Class name
      'parameters' => array(
        'test' => 'some data'
      )
    )
  )
);
 
use Zend\Di\Configuration;
 
$diConfig = new Configuration($config);
$di = new Di();
$diConfig->configure($di);

And we run our test code getting our ‘some data’ parameter, right?

1
string(9) "some data"

Yep.  Hmm, but what about getTestData()?

1
var_dump($test->getTestData());

echos

1
string(9) "some data"

Hmm, that shouldn’t be happening.  We did’t tell the DiC that we wanted to inject data there, did we?  It looks like it’s injecting data into both setter methods.  But why?

Look at the names of the parameters for both setters.  They are both named “test”.  The DiC will find the first method with a matching parameter name and inject the value there (if it couldn’t find it in the constructor) .  You have a couple of options to fix this.  If it’s your own code and you don’t mind refactoring, refactor it.  However, if it’s third party code that you shouldn’t touch or code that other parts of the system are dependent on, you have a problem.

But to get around the problem you can specify the setter parameter as a fully qualified (FQ) parameter (I show another , probably better, method here).  The format is “class::method:paramPos”.  In this example it would be “Test::setTest:0″.  So let’s change our DI configuration.

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

And now check the return values of both getters.

1
2
3
$test = $di->get('Test');
var_dump($test->getTest());
var_dump($test->getTestData());

Now we get

1
2
string(9) "some data"
NULL

Works.

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.