PHPBuilder - PHP Dependency Injection Creates More Maintainable Code



RSS Twitter
Articles Application Architecture

PHP Dependency Injection Creates More Maintainable Code

by: W. Jason Gilmore
|
April 29, 2011

Although not originally conceived as such, PHP has over the years evolved into a very capable object-oriented language, with countless enterprise projects and a number of powerful frameworks such as Symfony taking full advantage of these mature features. Of course, the advantages of object-orientation can only be fully exploited when implemented in conjunction with best practices such as encapsulation and inheritance. One such "implementational" best practice is dependency injection, a design pattern that facilitates the decoupling of otherwise dependent components.

Why is decoupling important? Consider a class named Account that represents a registered user account. Via the mysqli extension the Account class interacts with a database in order to create, retrieve, and update user accounts. A snippet of such a class might look like this:

class Account {

  private $_db;

  ...

  public function __construct($host, $user, $pswd, $db) {
    $this->_db = new mysqli($host, $user, $pswd, $db);
  }

  ...

  public function save() {
    ...
  }

}

So what's the problem? The Account class will not work without the mysqli extension, meaning the two are inextricably intertwined and must be used together in any future application. So much for reusability. Problems begin to compound when you learn that for a particular client you need to connect to a MySQL database that happens to run on a non-standard port (3306 is the default). As it happens, such an eventuality was considered and built into the mysqli constructor's signature, allowing you to pass the port in after the host, username, password, and database name, as demonstrated here:

$db = new mysqli("127.0.0.1", "webuser", "secret", "dev.example.com", 4522);

But how are you going to make this adjustment to accommodate the tight coupling found in the Account class? You could modify the Account constructor, and then pass the port number in as a constructor input parameter or perhaps set it via application constant. All such approaches require you to modify the Account class for reasons having nothing to do with the Account itself, but rather because of external dependencies. Save yourself the trouble and decouple components using dependency injection.

Using Dependency Injection in PHP

Dependency injection decouples components by moving the dependency instantiation outside of the class, and then injecting the dependency into the class, usually via the class constructor. Therefore the revised approach would look like this:

...
class Account {

  private $_db;

  ...

  public function __construct($db) {
    $this->_db = $db;
  }

  ...

}

$db = new mysqli($host, $user, $pswd, $db, $port);
$account = new Account($db);

In a nutshell, that simple but important refactoring summarizes the advantages to be had by using dependency injection! If what's been described so far isn't reason enough to begin using this approach, in addition to removing the inconveniences of modifying the dependent class to accommodate the changing dependency requirements, you gain an additional advantage of being able to swap out the dependency class altogether. If the dependency class were coded against an interface, then it would be entirely possible for the Account class to interact with a PostgreSQL database, LDAP, or any other data repository, provided the new class also correctly implements the interface requirements.


1
|
2
Next Page »

Comment and Contribute

Your comment has been submitted and is pending approval.

Author:
W. Jason Gilmore

Comment:



Comment:

(Maximum characters: 1200). You have characters left.