As I explained in the introduction, the logic that stands behind the Dependency Injection pattern is quite easy to grasp, and despite its intimidating name, implementing it in concrete cases is a no-brainer process. However, for you to understand why this pattern is so useful, in this first tutorial of the series I’m going to build a basic MySQL-driven program using a “wrong” approach that will make you see how the application of this pattern can turn into a “good” one rapidly. In this case, the program that I plan to develop will be composed of only two classes: the first one will be tasked with abstracting accesses to MySQL, while the second one will be charged with saving the properties of some fictional users to a specified database table. Also, it’s valid to clarify that I’ve used these example classes in other articles that I've written for the prestigious Developer Shed network, so you may find them familiar. Having clarified that point, here’s the definition of the class that interacts with MySQL, not surprisingly called “MySQL” too: class MySQL { private $result = NULL; private $link = NULL;
// 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); } } As seen above, this MySQL abstraction class defines some simple methods for running queries, fetching and counting rows in a data set and so forth. So far, there’s nothing especially relevant about the way that this class works, so let me show you the signature of the class that uses the previous “MySQL” to store its properties on a predefined database table. This whole new class looks like this: class User { private $data = array(); private $id = NULL; private $db = NULL;
// constructor public function __construct($id = NULL) { $this->db = new MySQL('host', 'user', 'password', 'database'); 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"); } } } Regardless of the fact that the definition of the previous “User” class may look rather complex, in reality its functionality is remarkably simple. It uses some of the magic methods included with PHP 5 to fetch and retrieve its properties from a “users” MySQL table. This is a simple way to create objects capable of persisting across different HTTP requests, due to the fact that their properties can be easily fetched and modified on a different web page. This process is partially illustrated by the following script: // create a user object $user1 = new User(); $user1->name = 'Alejandro Gervasio'; $user1->email = 'alejandro@domain.com';
// create another user object $user2 = new User(); $user2->name = 'Susan Norton'; $user2->email = 'susan@domain.com'; In this particular example, a couple of persistent objects have been successfully spawned by the two classes that you saw before. That was really easy to achieve! But, if everything looks good at this point, what could be so wrong with the previous script? Well nothing, to be frank. The problem is with the way that the “User” class utilizes the functionality of “MySQL” to have access to the corresponding database table, because it creates an instance of the database handler inside its constructor, which is stored as a $db property. In general this approach is considered inefficient, since “User” shouldn’t be responsible for constructing its own dependencies. Instead, it should receive those dependencies from the outside via a specific method. Period. This incorrect definition of the “User” class puts in evidence the need to have a mechanism that passes the database handler to the class’s internals. But I’m getting ahead of myself, since issue could be fixed with the dependency injection pattern. However, for the moment I’m going to keep the suspense going. In the following segment, I’m going to modify the definitions of the two classes shown previously, which will improve the way that they interact with each other. Now, click on the link below and keep reading.
blog comments powered by Disqus |
|
|
|
|
|
|
|