PHP Dependency Injection

by Ryan on January 8, 2009

Dependency injection is the answer to more maintainable, testable, modular code.

Every project has dependencies and the more complex the project is the more dependencies it will most likely have.  The most common dependency in today’s web application is the database and chances are if it goes down the application will all together stop working.  That is because the code is dependent on the database server, which is perfectly fine.  Not using a database server because it could one day crash is a bit ridiculous.  Even though the dependency has its flaws, it still makes life for the code, and thus the developer, a lot easier.

The problem with most dependencies is the way that code handles and interacts with them. What I really mean is the problem is in the code and not the dependency.  If you are not using dependency injection, chances are your code looks something like this:

class Book {
 
	public function __construct() {
 
		$registry  = RegistrySingleton::getInstance();
		$this->_database = $registry->database;
 
		// or
 
		global $databaseConnection;
		$this->_database = $database;
	}
 
}

The book object now is given full access to the database once it is constructed.  That is good, the book needs to be able to talk to the database and pull data.  The problem lies in the way the book gained its access.  In order for the book to be able to talk to the database the code must have an outside variable named $database, or worse, it must have a singleton pattern class (registry) object containing a record for a database connection.  If neither of these exist the book fails, making the code far from modular.

This raises the question, how exactly does the book get access to the database?  This is where inversion of control comes in.

In Hollywood a struggling actor does not call up a director and ask for a role in his next film.  No, the opposite happens.  The director calls up the actor and asks him to play the main character in his next movie.  Objects are struggling actors, they do not get to pick the roles they play, the director needs to tell them what to do.  Objects do not get to pick the outside systems they interact with, instead, the outside systems are given to the objects.  Remember this as Inversion of Control.

This is how a developer tells his objects how to interact with outside dependencies:

class Book {
 
	private $_databaseConnection;
 
	public function __construct() { }
 
	public function setDatabaseConnection($databaseConnection) {
		$this->_databaseConnection = $databaseConnection;
	}
 
}
$book = new Book();
$book->setDatabase($databaseConnection);

This code allows for the book class to be used in any web application.  The Book is no longer dependent on anything other than the developer supplying a database shortly after object creation.

This is, at its finest, dependency injection.  There are two common ways of injecting dependencies.  The first being constructor injection and the second being setter injection.  Constructor injection involves passing all of the dependencies as arguments when creating a new object.  The code would look something like this:

$book = new Book($databaseConnection, $configFile);

There are some issues with constructor injection. First, the more dependencies a class has the messier the constructor becomes. Passing in three or four dependencies all in a constructor is extremely hard to read. Also, the less work a constructor does the better.

This leaves us with our second method of dependency injection, setter injection. A dependency is set by using a public method inside the class.

$book = new Book();
$book->setDatabase($databaseConnection);
$book->setConfigFile($configFile);

This is easy to follow, but it leads writing more and more code for your application.  When a book object is created three lines of code are required.  If we have to inject another dependency, a 4th line of code is now needed.  This gets messy quickly.

The answer to this problem is a container, which is class that is designed to hold, create, and inject all the dependencies needed for an application or class.  Here is an example:

class Container {
 
	public static $_database;
 
	public static function makeBook() {
 
		$book = new Book();
		$book->setDatabase(self::$_database);
		// more injection...
 
		return $book;
	}
 
}

And then:

$book = Container::makeBook();

All dependencies should be registered into the container object during run time.  This object is now the gateway that all dependencies must pass through before they can interact with any classes.  This is the dependency container.

The reason makeBook is a public static function is for ease of use and global access.   When I started this article off I made a reference to the singleton pattern and global access being a poor choices of code.  They are, for the most part.  It is bad design when they control access, but it is perfectly ok when they control creation.  The makeBook function is only a shortcut for creation.  There is no dependency what-so-ever between the book class and the container class.  The container class exists so we can contain our dependencies in one location and automatically inject those dependencies with one line of code creation.

The container class removes all of the extra work of dependency injection. 

Before injection:

$book = new Book();

And now:

$book = Container::makeBook();

Hardly any extra work, but tons of extra benefits.

When test code is run, specifically unit tests, the goal is to see if a method of a class is working correctly.  Since the book class requires database access to read the book data it adds a whole layer of complexity.  The test has to acquire a database connection, pull data, and test it.  All of a sudden the test is no longer testing a single method in the book class, it is now also testing database.  If the database is offline, the test would fail.  This is far from the goal a unit test.

A way of dealing with this is just using a different database dependency for the unit tests.  When the test suite starts up a dummy database is injected into the book.  The dummy database will always have the data the developer expects it to have.  If a live database was used in a unit test the data could potentially change causing tests to unnecessarily fail. 

The code is more modular because it can dropped into any other web application.  Create the book object and inject a database connection with $book->setDatabase().  It does not matter if the database is in Registry::Database, $database, or $someRandomDatabaseVarible.  As long as there is a database connection the book will work inside any system.

The code is more maintainable because each object is given exactly what it needs.  If separate database connections are required between different instances of the same class then there no extra code needed inside the class what-so-ever.  Give book1 access to database1 and book2 access to database2.

Container::$_database = $ourDatabaseVarForDB1;
 
$book1 = Container::makeBook();
$book2 = Container::makeBook();
$book2->setDatabase($database2);

Dependency injection really is the answer to more maintainable, testable, modular code.


I titled this article PHP Dependency Injection, but there is really nothing in here that is specific to PHP.  The reason I choose to include PHP and write all of the code examples in PHP is because I constantly see PHP projects not using DI.  I believe the best place to teach good coding practices is in popular frameworks by forcing the users of the framework to develop within the guidelines of a certain pattern.  Take MVC for example, nowadays all developers understand it and most of the  underlying principles that accompany it.  This is because the frameworks they use force them to use MVC.

Also, please note that the code samples used in this article are just really simple examples to show the nuts and bolts of dependency injection and inversion of control. If you wish to implement injection into your project please take a look at an already built dependency injection framework.

38 Responses leave one →
  1. Don permalink
    February 13, 2009

    Huh?
    Constructor injection is bad? Tell the Pico guys, the’ll be happy.

    If a constructor gets too crowded, then you probably have a design problem.

    The problem with setter inejction is: you have to know what to set and if you forget something it would not work, often violating the whole object principle.
    Setter injection is good for optinal stuff, constructor for the required.

    Also having a constructor with five parameters or calling five setters make no big difference.
    In both cases it’s too much ;-)

  2. February 14, 2009

    i believe that no work should be done in your constructor, not even injection, so i am against it. code should be reusable and constructor code is not.

    the problem with constructor injection, in my eyes, is that it can only be done upon object creation and it can only be done once. this becomes troublesome when you are caching objects that have references to resource types (db connection, etc). reinjecting via a setter eliminates this problem. its allows for reusable code, which is going to make development life easier.

    i agree that 5 dependencies is way too much and bad. this was probably a bad example in my original piece. however, when dealing with multiple dependencies, setter injection is going to make the code more readable.

    tbh, i have no real problem with constructor injection. all of the respected di frameworks support it. i do think that when someone is leaning di that it is better to push setter injection down their throat, but they should also be made aware of how constructor injection works.

    thanks for the comments.

  3. February 14, 2009

    wow this blog does a great job of spacing paragraphs :)

  4. Matt permalink
    February 20, 2009

    Don and Ryan….great comments. Your comments show that both types of injection have their place, and DI frameworks should support both types. My soapbox: As a general rule of thumb, constructor injection should be limited to those dependencies that MUST be “set” before your object will work properly. Other dependencies can be done through setters, especially the dynamic ones as Ryan said. I’ve been working on an older Java codebase that uses the precursor to Spring (called interface21) that doesn’t have constructor injection. It would have helped with overall testability and design, especially.

  5. Kirk Bushell permalink
    May 10, 2009

    One thing I think that Don doesn’t realise (or maybe forgot to mention) is that constructor-based setting of dependencies makes unit testing more difficult, as you can’t mock out a constructor. I much rather use a setter method externally to create dependencies, as it makes your tests easier to write and as Ryan stated, makes it more readable – as you know exactly what’s going on without having to look inside the class.

  6. NIckG permalink
    May 14, 2009

    Good Stuff :)

    I’d say worth mentioning this;
    http://martinfowler.com/articles/injection.html

    “My long running default with objects is as much as possible, to create valid objects at construction time.

    Despite the disadvantages my preference is to start with constructor injection, but be ready to switch to setter injection as soon as the problems I’ve outlined above start to become a problem.”

  7. AK820 permalink
    May 19, 2009

    Nice article


    I agree to the point mentioned by Kirk and to take care of the must set attributes issue, you can always have constructor injection together with setter injection and a private constructor with methods that would provide you ways of creating a fully functional object v/s a mock object.
    I believe that design patterns are there primarily to make code management easier. Sticking with some pattern does not always solve the problem of code maintenance and scalability.

  8. Simon permalink
    August 9, 2009

    Hi there!

    I’d be happy if you could tell me which plugin you use to highlight your sourcecode!

    simon

  9. August 19, 2009

    simon,

    i am using google syntax highlighter

    http://code.google.com/p/syntaxhighlighter/

  10. idont permalink
    August 26, 2009

    Hi,

    For the setter/constructor dilema, here is a possible solution (Misko Hevery):
    * Constructor injection: injected class lifetime >= class lifetime
    * Setter injection: injected class lifetime <= class lifetime

    That way, the problems you discribe does not occur. :)

  11. Dave permalink
    September 17, 2009

    I understand what’s going on with DI, except this. In the example of using setter injection, Ryan mentioned creating two Book objects. Book1 would have access to database1, and Book2 would have access to database2. There is one lingering question in my mind…

    So, database1 and database2 are required to have the same interface? For instance, if you wanted to perform a query on database1, you might call a performQuery() function for retrieving data. With database2, the proper function might be executeQuery(). So, injecting dependencies forces rigid interface standards on the objects that are depended upon?

    Or am I totally off base?

  12. September 23, 2009

    Dave,

    The idea is that database1 and database2 are both the same class, but different objects (instances). We are not trying to write code that will fit with any interface, we only want to work with our interface.

    The reason we inject the different databases is because sometimes we are using a production database to pull real data, and other times we are using a mock database to test our code.

    Injection leaves it up to US, not the class, to decide which database to use. This gives us much greater long term flexibility as well as makes our objects loosely coupled.

  13. October 30, 2009

    Very useful, thanks.

  14. Martijn Dijksterhuis permalink
    November 11, 2009

    Thanks for sharing this. I found a mention of Dependency Injection on Brandon Savage’s PHP blog; but this explains it.

  15. David Nussio permalink
    February 16, 2010

    Dave,
    If you want to using database with different interface you can inject into the Book a data mapper object (http://martinfowler.com/eaaCatalog/dataMapper.html) instead the Database object.

  16. catchamonkey permalink
    March 17, 2010

    Good article, outlines well something entirely useful and interesting.
    Also, just because Zend doesn’t give you a DI container, doesn’t mean you can’t use it in your Zend apps. Just plugin the Symfony component

  17. Robert Cooke permalink
    May 16, 2010

    Hi,

    I’m using the setter injection, because I set up a very general Factory class for accessing my libraries and I wanted to keep that as simple as possible.

    After reading this I’m thinking of putting object specific factories between the general Factory and the objects I want to have so I can choose what to use setter/construct.

    Thank you,

    Robert

  18. harald permalink
    September 14, 2010

    thanks for this great article — it clarifies a lot of problems i was facing when trying to introduce DI into my framework. a question though:

    why do you use a container class — why don’t you add a static public makeBook method to the book class itself? are there any reasons for this?

    thanks again,

    harald

  19. Terry permalink
    October 7, 2010

    Would the container also be considered as a factory pattern

  20. October 10, 2010

    @harald: You do not want to have a public static makeBook method inside the book class, because that would mean we are no longer inverting dependency control.

    @terry: Yup, the container is also kind of a factory pattern. This is because it controls creation and build up of the objects. However, it is much more since it also holds the class’s dependencies.

  21. Timido permalink
    October 11, 2010

    Good article.
    A point where DI may cause some troubles is when you need some “external” function create your object.
    Say you have a ORM library which is passed your object class name to allow for it returning objects after a query to a database.
    Those returning objects will be instances of your Class, but they indeed need to be created thru your DI container!
    How would you handle this ?
    (ok, you may use a Value Object pattern, but lets assume you wanna have a Business Object and want it to be the one to be returned from the ORM layer)

    Hope I made the point enough clear.
    Thank you again!

  22. Lucky Luc permalink
    October 11, 2010

    This is exactly what I was looking for, I can’t begin to tell you how thankful I am =D

    Hello decoupling!

  23. October 11, 2010

    @ Timido: Excellent point. How do you integrate DI with 3rd party frameworks that do their own object creation? Most of these frameworks will allow you to register plugins to interact/control object creation. Lets stick with your ORM example… Doctrine (the best php orm, by far) allows you to register listeners/hydrators. With these, you are allowed to do anything to the objects after the ORM creates them (like inject all of the dependencies!). Just about every good framework provides a way of doing this.

  24. Pooyan permalink
    October 12, 2010

    I googled for Dependency Injection a lot. I have to say that this article does the best description of Dependency Injection in its simplest, yet most effective manner. Thanks to the author of this article. Keep up the good job.

  25. Tiddo permalink
    February 4, 2011

    Very nice article. However, I have just one question about this: you said singleton patterns are bad, and I think I can agree with you. However, I think global variables and pure static classes are even worse than singleton patterns. Using this design pattern, you’ll have to use either pure static classes, as in your container example, or you’ll have to use global variables for e.g. the database connection. Is there any way around this?

  26. jsonx permalink
    February 10, 2011

    Thank you. This is the best explanation of Dependency Injection i have ever seen.

  27. February 14, 2011

    Tiddo, it’s fine to use a singleton for creation, because the class/object you are creating is not dependent on that singleton.

  28. presario permalink
    March 24, 2011

    Ryan, you have done a very good job! Very nice article! Thank you!

  29. presario permalink
    March 24, 2011

    Please change “now a days” to “nowadays”.

  30. March 28, 2011

    presario, thank you, updated.

  31. 25cm permalink
    June 19, 2011

    Still usefull article, thx

  32. July 5, 2011

    Great article, many thanks for writing it.

    Thought: I agree with you that passing numerous arguments to a constructor can get unwieldy, and that using a setter gives you a cleaner approach.

    However, one might make the constructor more elegant to deal with. Instead of passing numerous arguments to the constructor, you might:

    * define an BookConfiguration Interface with various possible classes that implement it:
    ** AppBookConfiguration
    ** UnitTestBookConfiguration

    * have ONE constructor on your Book class which expects ONE argument of type “BookConfiguration” (one little-used feature of PHP 5 is you can actually type your arguments like you can in Java and other languages):

    class Book {

    private $_databaseConnection;

    public function __construct(BookConfiguration $configuration) {
    //BookConfiguration is an Interface. when you invoke the constructor,
    //you’ll actually be passing instances of either “AppBookConfiguration”
    //or UnitTestBookConfiguration which are concrete classes that implement
    // the BookConfiguration interface.

    $this->_databaseConnection = $configuration->getDatabaseConnection()

    }//Book Class Constructor

    }//Book Class

    A few advantages:

    * addresses the possible constructor mess you outlined
    * as you extend Book, and Book “requires more things to work”, you can simply still just extend your configuration class
    * preserves dependency injection and the ability to supply alternate configurations based on the environment in which the class is intantiated.
    * doesn’t require an extra container class to perform bootstrapping operations that are, in essence, still vital to the proper operation of your Book class.

Trackbacks and Pingbacks

  1. bitExpert Blog » Blog Archive » Dependency Injection everywhere
  2. Peer Review: Testable Code And Architecture | BrandonSavage.net
  3. Q&A: Answering Some Questions About Object-Oriented Programming | BrandonSavage.net
  4. Five (Good) Lessons The Government Teaches Us About Object-Oriented Programming | BrandonSavage.net
  5. ajmichels.com
  6. PHP Dependency – A PHP Dependency Injection Framework

Leave a Reply

Note: You can use basic XHTML in your comments. Your email address will never be published.

Subscribe to this comment feed via RSS