In the previous article, we discussed the need for a framework, or a set of tools and components that will help us manage our application. We decided on developing our own simple framework, and we listed some of the features we would need for our application. The first of these was a way to manage dependency injection. But what is dependency injection? What is a dependency?

What is a Dependency?

Let’s imagine we wanted are working with a class to store our users. In a previous article we looked at a very simple User class. All it did was hold the username of our user, and it gave us a method to retrieve the username from the class.

<?PHP
    class User {
        private $Username;

        public function __construct($Username){
            if(!is_string($Username)){
                throw new InvalidArgumentException('Username is not a valid string!');
            }
            $this->Username = $Username; 
        } 
        
        public function getUsername(){ 
            return $this->Username; 
        }
    } 
?>
Let’s now imagine we want to be able to store our user into a database. We create a database class that is able to save and our user information. We have called this class UserModel. Let’s have a look at how we could use it.
<?PHP
    class User {
        private $Username;
        private $UserModel;

        public function __construct($Username, $UserModel){
            if(!is_string($Username)){
                throw new InvalidArgumentException('Username is not a valid string!');
            }
            $this->Username = $Username; 
            $this->UserModel = $UserModel;
        } 
        
        public function getUsername(){ 
            return $this->Username; 
        }

        public function saveUser(){
            $this->UserModel->save();
        }  
    } 
?>

We created a new method called saveUser(), which needs access to our UserModel. To get access to the UserModel, we asked for it to be passed to our __construct method when the instance of our User class was created. We then stored that UserModel in a class variable so we can access it from within our User class. Our User class is now dependent on the UserModel class. It will not work without it! This is a simple example of a dependency.

In order to create an instance of our User class, with the username “mattpresland”, we would now need to run the following command.

<?PHP
	$UserModel = new UserModel();
	$User = new User('mattpresland',$UserModel);
?>
This may look ok, but now lets imagine we have created a number of users, in different locations in our application.
<?PHP //index.php
	$UserModel = new UserModel();
	$User = new User('mattpresland',$UserModel);
?>
<?PHP //dashboard.php
	$UserModel = new UserModel();
	$User = new User('mattpresland',$UserModel);
?>
<?PHP //roster.php
	$UserModel = new UserModel();
	$User = new User('mattpresland',$UserModel);
?>
<?PHP //messages.php
	$UserModel = new UserModel();
	$User = new User('mattpresland',$UserModel);
?>
<?PHP //reports.php
	$UserModel = new UserModel();
	$User = new User('mattpresland',$UserModel);
?>
If we now want to change the way the UserModel is constructed, lets say we need to pass a database connection to our UserModel class, which would make the call look like:
<?PHP
	$Database = new Database();
	$UserModel = new UserModel($Database);
	$User = new User('mattpresland',$UserModel);
?>

We would then have to go and update every single call to create our UserModel and User instances! If you missed just one change, your application would fail! Our User class is dependent on our UserModel class, which may be dependent on a Database class or any number of dependencies that may be introduced as the application grows. Yikes! So how can we manage our dependencies?

Dependency Injection Container

In order to better manage our dependencies, we can use a design pattern known as a dependency injection container. But what does that mean? We can create a class, who’s primary purpose is to return instances of each of our classes. Let’s have a look at how this could work. Below I have our current scenario, along with an example of how we could implement a very simple dependency injection container.

<?PHP //Our Current Code
	$Database = new Database();
	$UserModel = new UserModel($Database);
	$User = new User('mattpresland',$UserModel);
?>
<?PHP //Dependency Injection Container

	class Container {
		public function newDatabase(){
			$Database = new Database();    
			return $Database;
		}

		public function newUserModel(){
			$UserModel = new UserModel($this->newDatabase());
			return $UserModel;
		}

		public function newUser($Username){
			$User = new User($Username, $this->newUserModel());
			return $User;
		}
	}

	//To create an instance of our User class, we now only need to call
	$Container = new Container();
	$User = $Container->newUser('mattpresland');
	$User2 = $Container->newUser('mickeymouse');
?>

When we create a new instance of our User class, we now only need to call our newUser() method within our container class. Notice how we do not need to pass any dependencies in! Our container class knows how to create each of the dependencies, and will create them as needed to return an instance of the class we have requested. If we now want to change how a UserModel is constructed, we only need to change the getUserModel() method in our container class with the updated dependencies.

In other tutorials and articles, you may see further development of dependency injection containers in the form of registry type containers, where more generic methods are called, which look up a registry of classes and dependencies. An example of this can be seen at Envato Tuts+. I personally prefer more readable code, and as a result for our simple application I will stick with the example we have here.

Since we are using test based development, I have created an empty Database class, a UserModel class that depends on the Database Class, and I have made the UserModel class a dependency of our User class. I have then written a test to check that the UserModel attribute of our User class is an instance of the UserModel class, and likewise written a test for the UserModel class to ensure its Database attribute is an instance of the Database class.

The full class files, and tests are shown below. Note how when we now create an instance of our User class in our tests, we now first get an instance of our Container class, and then use Container->newUser()

<?PHP
	class Database{

	}

	class UserModel{
	   private $Database;
	   public function __construct($Database){
		   $this->Database = $Database;
	   }
	}

	class User{

		private $Username;
		private $UserModel;

		public function __construct($Username, $UserModel){
			if(!is_string($Username)){
				throw new InvalidArgumentException('Username is not a valid string!');
			}
			$this->Username = $Username;
			$this->UserModel = $UserModel;
		}

		public function getUsername(){
			return $this->Username;
		}
	}

	class UserTest extends PHPUnit_Framework_TestCase{

		public $TestUser;
		public $Container;

		public function setUp(){
			$this->Container = new Container();
			$this->TestUser = $this->Container->newUser('mattpresland');
		}

		public function testUserClassHasUsernameAttribute(){
			$this->assertClassHasAttribute('Username', 'User', 'The Class User does not have an attribute named Username');
		}

		public function testUsernameCanBeSet(){
			$this->assertAttributeNotEmpty('Username', $this->TestUser, 'Username is Empty');
		}

		public function testUsernameCanBeRetrieved(){
			$this->assertEquals('mattpresland', $this->TestUser->getUsername(), 'Username returned from getUsername does not match the expected Username');
		}

		public function testExceptionThrownForNonStringUsername(){
			$this->setExpectedException('InvalidArgumentException');
			$TestUser = $this->Container->newUser(1234);
		}

		public function testUserHasUserModelDependency(){
			$this->assertAttributeInstanceOf('UserModel', 'UserModel', $this->TestUser, 'User->UserModel is not an instance of UserModel');
		}
	}

	class UserModelTest extends PHPUnit_Framework_TestCase{

		public $Container;
		public $UserModel;

		public function setUp(){
			$this->Container = new Container();
			$this->UserModel = $this->Container->newUserModel();
		}
		public function testUserModelHasDatabaseDependency(){
			$this->assertAttributeInstanceOf('Database', 'Database', $this->UserModel, 'UserModel->Database is not an instance of Database');
		}
	}
?>

You can see that by simply calling $Container->newUser(‘mattpresland’); we get a user object that contains all of the dependencies it requires. We can now manage dependencies in our growing application much easier! We still room to improve however. Currently in order to create our objects, we need an instance of our Container class to be available. We could simply create an instance, and call on it each time, but what if we needed access to our container from within another object or class? Our instance of Container would not be in our new class’s scope. We could make our Container object a dependency, but that would not be very efficient, we could create a new instance within every class, also not very efficient, or we could use the global keyword to access an object outside of our class. This would cause nightmares if we ever needed to change the name of our Container object! We would ave to change all of our calls to the container.

Instead, we can utilise a PHP feature called static functions. Static functions allow you to call the static methods of a class, without creating an instance of the class. This means, as long as the class has been defined, we can access the static methods of the class. In order to use a function as a static function, we need to define it as one.

<?PHP //Dependency Injection Container

	class Container {
		public static function newDatabase(){
			$Database = new Database();    
			return $Database;
		}

		public static function newUserModel(){
			$UserModel = new UserModel(self::newDatabase());
			return $UserModel;
		}

		public static function newUser($Username){
			$User = new User($Username, self::newUserModel());
			return $User;
		}
	}

	//To create an instance of our User class, we now only need to call
	
	$User = Container::newUser('mattpresland');
	
?>

As you can see, we have added the static keyword to the declaration of our functions. We have also changed the call $this->newObject to self::newObject, which calls static functions of the current class. Finally, when we now wish to create a new user, we simply call Container::newUser(‘mattpresland’); which calls the newUser static function of the Container class. We can now call these static functions from any place in our application.

In our next article we will have a look at managing sessions so we can handle user logins and manage the state of our application.