The Pope Is Dead ::

Main Navigation

The pope is dead. Long live the pope! Just another blog about web development. If you’re interested in web stuff you may find this blog useful.

blog latest entries

New Zend_Application feature/update

Just noticed this in the trunk of ZF, probably in 1.10 too. You do not now need to register the default resource autoloader for your default module, you can now simply put appnamespace = “myNamepase” in the app config. This will register the default resources for your default module.

Posted on 22/12/2009 at 02:59 PM

New Storefront Example Additions

I have added search functionality to the Storefront example using Zend_Search_Lucene from the Zend Framework 1.8: Web Application Development book, I will hopefully get some time to write about this over christmas, for now though if you are interested you can download the code for the Google code sites trunk.

ZF Storefront Example on Google Code

svn checkout http://zendframeworkstorefront.googlecode.com/svn/trunk/ zendframeworkstorefront-read-only

Enjoy...

Posted on 13/12/2009 at 02:26 PM

Dependency Injection

For a while now I have been looking at Dependency Injection in PHP and have been experimenting with the Yadif DI Container, after much thought I decided to stop creating the article on ZF and Yadif as I now believe that in PHP a DI Container is overkill. This article is therefore an explaination of the general DI principles that we all can use to improve our code and why DI Containers are overkill in PHP.

Dependency injection (the problem)

Dependency Injection is a design pattern that deals with object configuration or object dependencies. By a dependency we mean that an Object uses another Object or Service, this brings us to the problem of how an Object handles it supporting services. The easiest way to look at this is through an example, consider the following class.

© 2010 Keith Pope
  1. class Foo
  2. {
  3.     protected $_db;
  4.    
  5.     public function __construct()
  6.     {
  7.         $this->_db = new dbConnection();
  8.     }
  9.  
  10.     // other methods..
  11. }
Parsed in 0.008 seconds, using GeSHi 1.0.7.21

In class Foo we need to use the supporting database connection, to do this we instantiate a new dbConnection class in Foo’s constructor. This seems like a totally reasonable way to give our class access to the database connection, however by doing this we are giving Foo control over its own configuration (dependencies); this causes us the following problems.

  • We cannot replace the database dbConnection instance when testing as we have no control over its instantiation.
  • Foo must know how to configure the database connection which breaks the encapsulation of our object.
  • We cannot easily change the dependencies of Foo, to do so we must edit the code.

So basically when we have a new call within our class we create a tight coupling between our objects. To solve this problem we need to configure the object from the outside rather than from within, we can do this using Dependency Injection which injects the dependencies into the object and takes control over the objects dependencies.

Types of dependency injection

To start we will look at some basic types of Dependency Injection, we can easily use these techniques in any application without the need for a Dependency Injection framework, though we still use these techniques even with a framework.

Constructor based injection

Constructor injection is where we inject our dependencies via the objects constructor method; if we now go back to the Foo example we can refactor that class to support constructor injection.

© 2010 Keith Pope
  1. class Foo
  2. {
  3.     protected $_db;
  4.    
  5.     public function __construct(dbConnection $db)
  6.     {
  7.         $this->_db = $this->_db = $db;
  8.     }
  9.  
  10.     // other methods..
  11. }
Parsed in 0.008 seconds, using GeSHi 1.0.7.21

We can see that we have only had to make minor changes to the class to implement constructor injection. To do this we now pass the dbConnection class into Foo via a constructor parameter, meaning to use Foo we now do:

© 2010 Keith Pope
  1. $foo = new Foo(new dbConnection());
Parsed in 0.004 seconds, using GeSHi 1.0.7.21

The dbConnection class is now injected into Foo, meaning we can easily replace it and have removed the responsibility of instantiation from Foo.

As we can see this is very simple and I am sure we have all already done similar things in our code but maybe without knowing. We can also further improve this by introducing an interface, currently the constructor parameter is type hinted as dbConnection meaning we can only pass in instances of dbConnection or subclasses of it.

© 2010 Keith Pope
  1. interface IdbConnection
  2. {}
  3.  
  4. class myDbConnection implements IdbConnection
  5. {}
  6.  
  7. class testDbConnection implements IdbConnection
  8. {}
  9.  
  10. class Foo
  11. {
  12.     protected $_db;
  13.    
  14.     public function __construct(IdbConnection $db)
  15.     {
  16.         $this->_db = $this->_db = $db;
  17.     }
  18.  
  19.     // other methods..
  20. }
Parsed in 0.013 seconds, using GeSHi 1.0.7.21

By introducing an interface for dbConnection we can now easily create many different types of dbConnection that Foo can use, Foo will know how to use each connection type as they will all share the same public interface. Generally this is good practice when injecting dependencies as it make our implementation much more flexible.

Setter based injection

Setter based injection is just as simple as constructor based injection, however this time rather than providing our dependencies in the construct we provide them using a setter method.

Going back to our example we can refactor Foo to use setter injection.

© 2010 Keith Pope
  1. class Foo
  2. {
  3.     protected $_db;
  4.    
  5.     public function __construct()
  6.     {}
  7.  
  8.     public function setDb(IdbConnection $db)
  9.     {
  10.         $this->_db = $db;    
  11.     }
  12.  
  13.     public function getDb()
  14.     {
  15.         return $this->_db;
  16.     }
  17.  
  18.     // other methods..
  19. }
Parsed in 0.012 seconds, using GeSHi 1.0.7.21

We can see this is a fairly simple refactoring of Foo, this time we can inject our dependency via the setter and retrieve it via its getter. So which type of injection is best? Well really both are valid, using constructor based injection you can be certain that your dependency will not be forgotten to be injected as they are required to instantiate the object, with setter based injection you could forget to inject your dependency. However, with setter based injection you can get around this using Lazy Injection, which we will look at next.

Lazy injection

When using setter based injection we could possibly forget to inject a dependency, also if we have a large amount of dependencies our code could look like this:

© 2010 Keith Pope
  1. $foo = new Foo();
  2. $foo->setDb($db);
  3. $foo->setCache($cache);
  4. $foo->setLog($log);
Parsed in 0.007 seconds, using GeSHi 1.0.7.21

An awful lot to remember when instantiating an object, also we are lazy programmers so we never want to type this much!

© 2010 Keith Pope
  1. class Foo
  2. {
  3.     protected $_db;
  4.    
  5.     public function __construct()
  6.     {}
  7.  
  8.     public function setDb(IdbConnection $db)
  9.     {
  10.         $this->_db = $db;    
  11.     }
  12.  
  13.     public function getDb()
  14.     {
  15.         if (null === $this->_db) {
  16.             $this->_db = new dbConnection();
  17.         }
  18.         return $this->_db;
  19.     }
  20.  
  21.     // other methods..
  22. }
Parsed in 0.021 seconds, using GeSHi 1.0.7.21

Here we have simply added an if statement into the getter method for the database connection and if the _db property has not already been set we instantiate a new default dbConnection object. This affectively lazy loads our dependency for us if we have not already set one. By no means is this a perfect solution to our problem, what if we need to configure the dependent class too? Well, we then get horrible situations where we have configuration code with our classes or code that fetches the configuration or we go for more lazy configuration and so forth. So this is not perfect but at least it does solve some of our problems, this is why you will notice that I use it a lot in the Storefront application!

Unified Constructor

Another important technique to note is the Unified Constuctor, this is used in many ZF components already and provides a powerful way to configure an object. Whilst this is not strictly Dependency Injection we should be aware of it as it can be used in conjunction with Lazy Injection to good affect.

The idea of a unified Constuctor is to allow options/config to be passed into the constructor of the object that requires configuration, this then creates a construct that looks the same for many objects giving us the unified name.

To fully explain lets look at an example.

© 2010 Keith Pope
  1. class Foo
  2. {
  3.     protected $_db;
  4.  
  5.     public function __construct($options)
  6.     {
  7.         $this->setOptions($options);
  8.     }
  9.    
  10.     public function setOptions($options)
  11.     {
  12.         if ($options instanceof Zend_Config) {
  13.             $options = $options->toArray();
  14.         } elseif (!is_array($options)) {
  15.             throw new Exception('setOptions() expects either an array or a Zend_Config object');
  16.         }
  17.  
  18.         foreach ($options as $key => $value) {
  19.             $method = 'set' . ucfirst($key);
  20.             if (method_exists($this, $method)) {
  21.                 $this->$method($value);
  22.             }
  23.         }
  24.     }
  25.    
  26.     public function setDb(IdbConnection $db)
  27.     {
  28.         $this->_db = $db;    
  29.     }
  30.  
  31.     public function getDb()
  32.     {
  33.         if (null === $this->_db) {
  34.             $this->_db = new dbConnection();
  35.         }
  36.         return $this->_db;
  37.     }
  38. }
Parsed in 0.050 seconds, using GeSHi 1.0.7.21

So here we can see that Foo now accepts $options in its construct, $options will be either and array or Zend_Config instance that contains the objects configuration. The setOptions() method is called from the construct and simply iterates over the $options array and calls the setters that match the keys in that array. This means that along with the Lazy Injection we can now override the default database connection using the unified construct.

© 2010 Keith Pope
  1. $opts = array('db' => new MyDbConnection());
  2. $a = new Foo($options);
Parsed in 0.010 seconds, using GeSHi 1.0.7.21

This again lets us configure our objects from outside and breaks up those tight dependencies, there are some obvious drawbacks to the unified construct mainly that intellisense does not work and the code is not as clear as it could be as you need to know what the options are, though they do match the setters anyway.

Dependency Injection Containers

At this point I was going to show how we can use the Yadif DI Container to move all object configuration outside of our objects, however as I mentioned earlier after some discussion and research I now believe that the use of a DI container in PHP may be overkill in most situations.

So what does a DI Container look like?

© 2010 Keith Pope
  1. $container = new DIContainer($config);
  2. $foo = $container->getObject('Foo');
Parsed in 0.006 seconds, using GeSHi 1.0.7.21

The $config variable would contain a set a configuration instructions that tells the container how various object or components should be instantiated and configured. Therefore, we would retrieve all new objects via the container and would never use new to instantiate our objects, pushing all instantiation and wiring to the container.

So whats the problem? This does look like a very reasonable approach when you have many dependencies, however as PHP is a dynamic language that is generally used in a web environment we have a problem with the amount of objects that are created and potentially never used. Consider the following diagram.

If we were to retrieve A from the DI Container the Container would automatically instantiate six other objects, these in turn could create other objects and so on. This in PHP can become impractical as generally we are running in a stateless environment and many of these objects may never be used and take up memory. In Java this approach does not matter so much as it is stateful and eventually the objects will be used.

With this in mind I would only use a DI Container if you are running PHP in some sort of stateful environment. For now I would suggest using a combination of Lazy Injection, Unified Constructor and Factories to wire you objects, though a small DI Container used carefully can still be helpful.

Conclusion

A big part of Dependency Injection is helping us to create testable code, all the manual DI techniques I have covered here help to create a testable codebase even without the use of a DI Container. Remember the biggest killers for testable code are:

  • Global State
  • new calls within your code
  • Singletons (these are global state)
  • Static calls (global state again...)
  • PHP Function calls (global state yet again...)

So to sum up, Dependency Injection techniques are very valuable in our day-to-day programming, enabling us to create easy to test code. DI Containers probably should be used only with great care in PHP.

Footnote 1: If you are interested in Yadif or want to see a DI Container in action I have released code for the Storefront which I used in my experiments. Google Code - Yadif & Storefront

Footnote 2: Remember we can use Lazy Injection to guard against all the bad things for testability not just new calls.

Footnote 3: To guard against PHP core function cores which are in the Global Scope we can make a proxy class.

© 2010 Keith Pope
  1. class Php_Proxy
  2. {
  3.     public function __call($method, $args)
  4.     {
  5.         if (!function_exists($method)) {
  6.             throw new Exception('Function : ' . $method . ' not found');
  7.         }
  8.         return call_user_func_array($method, $args);
  9.     }
  10. }
  11. // We can then use the class like this
  12. $proxy = new Php_Proxy();
  13. $proxy->mysql_query('SELECT * FROM x');
Parsed in 0.026 seconds, using GeSHi 1.0.7.21

By creating a class that proxies to the global PHP functions we can now cleany replace calls to them within our classes during testing.

Posted on 09/12/2009 at 09:10 PM

Previous Entries  

about me

I am a web developer/ project manager from Birmingham Uk, currently I am working for inflight productions as a technical project manager. Hopefully I will be posting here as regularly as possible on my experiences with various technologies that I am using and maybe the odd random thing..

the book