Dependency Injection in PHP


Posted on May 7th, 2014


Dependency Injection is a software design pattern that allows avoiding hard-coding dependencies and makes possible to change the dependencies both at runtime and compile time. 

Every project will have lots of classes. Few classes will depend on other classes.  For example, we have a Library class which gets the name of the books from the database. So our library class is dependent on the database class.

<?php

include_once 'db.class.php';

class Library {
	
	private $_database;
	
	public function __construct() {

		$db  = DB::getInstance();
		$this->_database = $db->database;
		
	}
 
}

?>

In the above example,  the library object will have full access to database which is what we want. But the way, we are providing this access is not great.

The Library class is tightly coupled with the Database class, and while this might not look bad on this particular example. Let’s imagine that we want to reuse the Library class elsewhere, it will fail if the database class is not included.

Now lets look at this code.

<?php

class Library {
	
	private $_database;
	
	public function __construct($database) {

		$this->_database = $database;
		
	}
 
}

/* And this is how we initiate */

$lib = new Library($database);

?>

That’s a nice way of injecting the Database class inside the Library class.  And the Library class can now be used in any application. We just have to pass the database object to the Library class to the application. But what if the parameters are more in the constructor ?

Like this:

$library = new Library($database, $subscriptions, $books);

Over the time it gets messy.  I don’t like this much.

So the next good way to take over this situation is by using the setter injection.

<?php

class Library {
	
	private $_database;
	private $_books;
	
	public function __construct() {}
	
	public function set_database($database) {
		
		$this->_database = $database;
	
	}
	
	public function set_books($books) {
		
		$this->_books = $books;
	
	}

        public function createLibrary() {
		
		return "Library created from {$this->_database}";
	
	}
 
}

/* And this is how we initiate */

$lib = new Library();
$lib->set_database($database);
$lib->set_books($books);

?>

This is way too nice and neat. But you will soon realize that over the period of time, this will start smelling bad. If you have to use this class at 5 different places, you will have to initiate this 5 times, writing the same code. That’s crap.

What now ? We need something that is more robust and can control class initialization at one place.  Lets look at the below code.

class Container {
 
	public static $_database;
 
	public static function getLibrary() {
 
		$library = new Library();
		$library->set_database(self::$_database);
		$library->setBooks(new Book);
 
		return $library;
	}
 
}

We can then call this by:

$library= Container::getLibrary();

This code is much more flexible and it has lot of benefits. Lets say you want to access books from two different database.

Container::$_database = "db1";
 
$library = Container::getLibrary();
$lib1 = $library->createLibrary();


$library->set_database("db2");
$lib2 = $library->createLibrary();

 

 

Dependency injection really is the answer to more maintainable, testable, modular code. Its very easy to do unit tests with such modular code. 

Conclusion:

According to me, the constructor should not be overloaded with parameters.  Its better to inject the dependencies as and when required. However few users prefer to pass everything together in the constructor for easy tracing. So this might differ from users to users. Dependency Injection greatly reduces cost in the long run and makes the code highly scalable with less effort.

 


Eaglehorn FrameworkTutorial: AngularJS Fundamentals

Comments
100% Complete