PhpRiot
News Archive
PhpRiot Newsletter
Your Email Address:

More information

Learning About Dependency Injection and PHP

Note: This article was originally published at Planet PHP on 19 May 2011.
Planet PHP

Over the past few years, there are a few concepts and programming patterns that have muscled their way into the hearts and minds of PHP developers from other languages and programming communities. These concepts range from the MVC application architecture as well as various modeling techniques (think ActiveRecord and Data Mapper), to a pure shift in the way we think about application architectures, like aspect-oriented programming (AoP) and event-driven programming. Perhaps it's because PHP has been adopted at an enterprise level thus increasing the demand for what developers might call enterprise quality programming patterns, or perhaps it's simply because of PHP's ever evolving object model that makes new things possible. After all, who doesn't like new shiny things? Whatever the reason, one of the newest concepts (at least over the past 3 years or so) that has emerged as one of our heated topics of debate is how to manage object dependencies. Interestingly, the argument of how to manage dependencies is generally named by the solution which it's proponents give as the solution: dependency injection (the abstract principle is actually called Inversion of control).

In any circle of developers that are of the object-oriented persuasion, you'll never hear an argument that dependency injection itself, is bad. In these circles, it is generally accepted that injecting dependencies is the best way to go. Injecting object dependencies in PHP looks like this:

// construction injection $dependency = new MyRequiredDependency; $consumer = new ThingThatRequiresMyDependency($dependency);

That's basically it. There are many variations of this: setter injection, interface injection, call time injection, in addition to the above mentioned constructor injection. These are all valid ways of injecting the dependencies into the consuming object. Ultimately, the goal here is to avoid this:

class ThingThatHasAnExternalDependency { public function __construct() { $this-dependency = new ARequiredDependency; // or $this-secondDependency = ARequiredDependency::getInstance(); } }

The above code is an example of a violation of the Hollywood Principle, which basically states: aoDon't call us, we'll call you.a.

Yet, this is not the heart of the argument. Perhaps it was 4-5 years ago in the PHP community, but it's not anymore. The heart of the argument is not should we be doing it, but how do we go about doing it.

This article is not about the intricacies and implementation details of DI containers and DI frameworks. It's also not about the various ways and means of injection dependencies into other objects, and which method might be better. In fact, this article has no opinion if injecting dependencies is even good for you or your application. This article is an exploration how adopting any DI framework for PHP affects the lifecycle of a project, both the code as well as the developer, team or organization that is constructing it.

A Brief History of Dependency Management In PHP

It is important to know why PHP is as popular as it is, after all, it's this popularity that DI Frameworks fight against for adoption inside a PHP application framework. To understand PHP's popularity, history, and evolution, let's look at this code:

// these 6 lines actually represent 5 different web centric "langauges"! include_once 'includes/config.php'; // ultimately there is a mysql_connect() call in here somewhere include_once 'templates/header.php'; $rows = mysql_query('SELECT * FROM users'); // magically uses the mysql_connect() resource foreach ($rows as $row) { echo '' . $row['username'] . ''; } include_once 'templates/footer.php';

From the beginning, we've been trained into thinking that our dependencies are magically managed. As you can see above, the mysql_query() function, while it will accept a connection resource, does not require it. In fact, if it's not supplied, it will use the first open mysql connection it can find inside the PHP runtime. Assuming that the above mentioned delete-user.php script is part of a larger collection of PHP scripts, which we will call aothe applicationa a it is important to note that even this script itself is pulling in it's dependencies instead of them being inject

Truncated by Planet PHP, read more at the original (another 16174 bytes)