Injecting Objects Using Setter Methods with the Dependency Injection Design Pattern

In this third article of a six-part series, you will learn how to implement the dependency injection pattern by using a simple setter method. This process is very similar to the one that uses a constructor, which we covered in the previous article.

One of the most common tasks that many PHP 5 programmers must tackle during the development of object-oriented web applications is defining the way that objects are going to interact with each other. While this process seems to be a no-brainer one at first sight, the truth is that in real-world conditions it can be an extremely challenging and daunting experience.

Sad but true, a small application initially conceived to use some scarce classes can quickly become a confusing, messy maze as it grows in size and complexity, where certain objects are responsible for creating other objects here and there, without any type of restriction or predefined order. If you’ve ever reached that point as a PHP developer, then you know that you’ve been knocking on hell’s doors.

Fortunately, there’s a proven solution for a situation like this, which is incredibly simple to implement, called dependency injection. As the name suggests, this pattern permits you to define, through a few straightforward approaches, the way that classes will take in their dependencies, without compromising class encapsulation.

Due to the schema imposed by this pattern, it actively promotes the application of the Inversion of Control principle. This principle dictates that the environment is always responsible for providing objects with their dependencies, and not the other way around.

Of course, if you already read the previous part of this series, then you have a clearer idea on how to use dependency injection when working with a database handler and a class that needs it to build persistent objects.

In that example in particular, the database handler (read the dependency) was passed to the persistent class via its constructor method, which is one of the simplest ways to implement the pattern. Though, as I said before, dependency injection can be accomplished by using several approaches, including one that uses a setter method to pass the dependency of a given object.

In the next few lines I’m going to explain how to translate this last approach to functional PHP 5 code. Now, let’s continue exploring the benefits of using the dependency injection pattern. Let’s go!

{mospagebreak title=Review: implementing the dependency injection pattern using a constructor method}

Before I explain how to apply the dependency injection pattern by using a setter method, it’d be helpful to review the sample application developed in the preceding article. It implemented another version of the pattern by utilizing a constructor.

Having said that, here’s the complete definition of the MySQL abstraction class, whose instance needs to be injected straight into the internals of a couple of persistent objects. Check it out:

class MySQL

{

private $result = NULL;

private $link = NULL;

private static $instance = NULL;

 

// returns a singleton instance of MySQL class (chainable)

public static function factory($host, $user, $password, $database)

{

if (self::$instance === NULL)

{

self::$instance = new MySQL($host, $user, $password, $database);

}

return self::$instance;

}

// connect to MySQL

public function __construct($host, $user, $password, $database)

{

if (FALSE === ($this->link = mysqli_connect($host, $user, $password, $database)))

{

throw new Exception(‘Error : ‘ . mysqli_connect_error());

}

}

 

// perform query

public function query($query)

{

if (is_string($query) AND empty($query) === FALSE)

{

if (FALSE === ($this->result = mysqli_query($this->link, $query)))

{

throw new Exception(‘Error performing query ‘ . $query . ‘ Error message :’ .mysqli_error($this->link));

}

}

}

 

// fetch row from result set

public function fetch()

{

if (FALSE === ($row = mysqli_fetch_assoc($this->result)))

{

mysqli_free_result($this->result);

return FALSE;

}

return $row;

}

 

// get insertion ID

public function getInsertID()

{

return mysqli_insert_id($this->link);

}

// count rows in result set

public function countRows()

{

if ($this->result !== NULL)

{

return mysqli_num_rows($this->result);

}

}

// implement destructor to close the database connection

function __destruct()

{

mysqli_close($this->link);

}

}

The clock is ticking, so I’m not going to spend a long time explaining the full details for how this MySQL-handling class works, since you already know this. Instead, let me go one step further and show you the signature of the persistent class that uses the functionality of the previous database handler to do its business Here it is:

class User

{

private $data = array();

private $id = NULL;

private $db = NULL;

 

// constructor

public function __construct(MySQL $db, $id = NULL)

{

$this->db = $db;

if ($id !== NULL)

{

$this->id = $id;

$this->db->query(‘SELECT * FROM users WHERE id=’ . $this->id);

$this->data = $this->db->fetch();

}

}

 

// set undeclared property

public function __set($property, $value)

{

if ($property !== ‘name’ and $property !== ‘email’)

{

return;

}

$this->data[$property] = $value;

}

 

// get undeclared property

public function __get($property)

{

if (isset($this->data[$property]) === TRUE)

{

return $this->data[$property];

}

}

 

// save object to session variable

public function __destruct()

{

if ($this->id === NULL)

{

$this->db->query("INSERT INTO users (id, name, email) VALUES (NULL, ‘$this->name’, ‘$this->email’)");

}

else

{

$this->db->query("UPDATE users SET name = ‘$this->name’, email = ‘$this->email’ WHERE id = $this->id");

}

}

}

Definitely, the most relevant method of the above “User” class to look at is its constructor. It accepts an instance of the “MySQL” class to have access to its storage “users” table. This method itself shows clearly how simple and efficient it is to use dependency injection through a constructor; in this case, the process is easy to achieve thanks to the type hinting feature included with PHP 5.

Finally, here’s a short script that illustrates how the pattern is used to build two persistent objects:

// example of dependency injection via the constructor

// create instance of MySQL class

$db = new MySQL(‘host’, ‘user’, ‘password’, ‘database’);

// create first user object

$user1 = new User($db);

$user1->name = ‘Alejandro Gervasio';

$user1->email = ‘alejandro@domain.com';

 

// create second user object

$user2 = new User($db);

$user2->name = ‘Mary Smith';

$user2->email = ‘mary@domain.com';

This isn’t rocket science, but it works like a charm. As you can see, due to a proper implementation of the dependency injection pattern, the persistent objects just created are no longer responsible for spawning an instance of the database handler.

They suddenly became passive entities that expect to receive their dependency or dependencies from their context. Isn’t that good and effective? You bet it is.

Well, having exemplified the use of dependency injection by means of a constructor, it’s time to move forward and continue exploring other approaches that can be used to produce the same result. Therefore, according to the concepts deployed in the introduction, in the next section I’m going to discuss how to implement this pattern using a simple setter method.

To learn more about this process, please click on the link that appears below and keep reading.

{mospagebreak title=Using dependency injection via a setter method}

As I stated in the preceding section, it’s possible to implement the Dependency Injection pattern by means of a setter method, instead of using a constructor. This approach can be handy in those cases where a given class needs to take in multiple dependencies to work properly.

However, to demonstrate the implementation of this specific approach I’m going to reuse the couple of sample classes shown previously, so you can spot the difference between injecting dependencies via a constructor and via a setter method.

Now it’s necessary to modify the definition of the persistent “User” class and add to it the setter method. Here’s the modified version of this class:

class User

{

private $data = array();

private $id = NULL;

private $db = NULL;

 

// implements dependency injection via a setter method

public function setDatabaseHandler(MySQL $db)

{

$this->db = $db;

}

 

// initialize user object

public function load($id = NULL)

{

if ($id !== NULL)

{

$this->id = $id;

$this->db->query(‘SELECT * FROM users WHERE id=’ . $this->id);

$this->data = $this->db->fetch();

}

}

// set undeclared property

public function __set($property, $value)

{

if ($property !== ‘name’ and $property !== ‘email’)

{

return;

}

$this->data[$property] = $value;

}

 

// get undeclared property

public function __get($property)

{

if (isset($this->data[$property]) === TRUE)

{

return $this->data[$property];

}

}

 

// save object to session variable

public function __destruct()

{

if ($this->id === NULL)

{

$this->db->query("INSERT INTO users (id, name, email) VALUES (NULL, ‘$this->name’, ‘$this->email’)");

}

else

{

$this->db->query("UPDATE users SET name = ‘$this->name’, email = ‘$this->email’ WHERE id = $this->id");

}

}

}

 

As seen above, now the “User” class implements a brand new method called “setDatabaseHandler().” This method is responsible for taking from outside an instance of the database handler, and then saving this object as a class property.

If you ever thought that applying the dependency injection pattern using a setter method was a difficult process, then feel glad to know that you were wrong!

And now that you’ve surely grasped the logic that drives the above “User” class, it’s time to code an example that shows how to use it in conjunction with its dependency, that is, the corresponding MySQL database handler.

So, with that goal in mind, in the next section of this tutorial I’m going to create that example for you, thus finishing this introduction to applying dependency injection through a setter method. Now, click on the link that appears below and read the following segment, please.

{mospagebreak title=The dependency injection pattern in action}

In the previous section you saw how easy it is to use a setter method for passing the MySQL database handler to the internals of the persistent “User” class. Nonetheless, the best way to understand this process is by example, right? Thus, below I coded one for you that demonstrates how to create two persistent objects in a snap.

Take a look at the following code fragment:

// create instance of MySQL class

$db = new MySQL(‘host’, ‘user’, ‘password’, ‘database’);

// create first user object

$user1 = new User();

$user1->setDatabaseHandler($db);

$user1->load();

$user1->name = ‘Alejandro Gervasio';

$user1->email = ‘alejandro@domain.com';

 

// create second user object

$user2 = new User();

$user2->setDatabaseHandler($db);

$user2->load();

$user2->name = ‘Mary Smith';

$user2->email = ‘mary@domain.com'; 

Here you have it. Thanks to the implementation of dependency injection via a setter method, it’s extremely simple to build two trivial persistent objects. Also, it’s quite possible that you find the approach that utilizes a constructor a little bit cleaner, but when a class requires multiple dependencies, probably a setter method is a better option.

Finally, feel free to tweak all of the code samples shown in this article, so you can get a more intimate knowledge of applying the dependency injection pattern by means of a setter method.

Final thoughts

In this third article of the series, you hopefully learned how to implement the dependency injection pattern by using a simple setter method. As you saw for yourself, this process is very similar to the one that uses a constructor, so in theory you shouldn’t have major problems understanding its driving logic.

In the next chapter, things will get even more interesting. I plan to demonstrate how to use dependency injection within a PHP 5-based application that works with the popular Model-View-Controller pattern.

Don’t miss the forthcoming article!

[gp-comments width="770" linklove="off" ]

chat