views:

328

answers:

5

I hear people talking about dependency injection and the benefit of it all the time, but I don't really understand it.

I'm wondering if it's a solution to the "I pass database connections as arguments all the time" problem.

I tried reading wikipedia's entry on it, but the example is written in Java so I don't solidly understand the difference it is trying to make clear. ( http://en.wikipedia.org/wiki/Dependency_injection ).

I read this dependency-injection-in-php article ( http://www.potstuck.com/2009/01/08/php-dependency-injection/ ), and it seems like the objective is to not pass dependencies to an object directly, but to cordon off the creation of an object along with the creation of it's dependencies. I'm not sure how to apply that in a using php functions context, though.

Additionally, is the following Dependency Injection, and should I bother trying to do dependency injection in a functional context?

Version 1: (the kind of code that I create, but don't like, every day)

function get_data_from_database($database_connection){
    $data = $database_connection->query('blah');
    return $data;
}

Version 2: (don't have to pass a database connection, but perhaps not dependency injection?)

function get_database_connection(){
    static $db_connection;
    if($db_connection){
        return $db_connection;
    } else {
        // create db_connection
      ...
    }
}

function get_data_from_database(){
   $conn = get_database_connection();
   $data = $conn->query('blah');
   return $data;
}

$data = get_data_from_database();

Version 3: (the creation of the "object"/data is separate, and the database code is still, so perhaps this would count as dependency injection?)

function factory_of_data_set(){
    static $db_connection;
    $data_set = null;
    $db_connection = get_database_connection();
    $data_set = $db_connection->query('blah');
    return $data_set;
}

$data = factory_of_data_set();

Anyone have a good resource or just insight that makes the method and benefit -crystal- clear?

+5  A: 

None of your examples look like dependency injection, version one is the closest though. Dependency injection is a technique used in object oriented programming, where the constructor of an object has arguments for the service objects it needs, and those service objects are passed in by the creator of the instance (which could be a factory, a test, or a dependency injection framework).

To get around your 'always passing the connection object' problem you may want to consider the template pattern. The template pattern is basically an abstract base class with the common part of a repeated code block, and abstract methods to allow for the variation between the instances of those repeated code blocks. Basically the base is a template of a block of code, and the abstract methods are the blanks to be filled in. I personally use the template method pattern to do my database resource control in Java.

Sarah Happy
http://en.wikipedia.org/wiki/Template_method_pattern ?
Tchalvak
one of the possible implementations of that, yes.
Sarah Happy
A: 

how about this? http://phpcrafty.sourceforge.net/

Nir Gavish
A: 

I find that the following link contains an useful intro to dependency injection, maybe you will find it useful too.

http://components.symfony-project.org/dependency-injection/trunk/book/01-Dependency-Injection

Maybe you will find useful also this text from Martin Fowler's site. It is a bit old but clearly states the differences between three different kinds of dependency injection (depending on how it is started)

http://www.martinfowler.com/articles/injection.html

Eineki
+3  A: 

Your first example IS dependancy injection, you are injecting the dependency on the database object into the function.

Sarah has said this isn't, but imo it is, I believe she is thinking of dependency injection containers which are the next level up:

http://components.symfony-project.org/dependency-injection/trunk/book/02-Dependency-Injection-Containers

jmoz
+5  A: 

Database injection is a big word for "I have some more parameters in my constructor".

It's what you did before the awfull Singleton wave when you did not like globals :

<?php
class User{
  private $_db;
  __construct($db){
    $this->_db = $db;
  }
}

$db = new Db();
$user = new User($db);

Now, the trick is to use a single class to manage your dependencies, something like that :

<?php
class DependencyContainer{
  private _instances = array();
  private _params = array();

  public function __construct($params){
    $this->_params = $params;
  }

  public function getDb(){
    if(empty($this->_instances['db']) ||
       !is_a($this->_instances['db'], 'PDO')){
      $this->_instances['db'] = new PDO($this->_params['dsn'], $this->params['dbUser'], $this->params['dbPwd']);
    }
    return $this->_instances['db'];
  }
}

class User{
   private $_db;
   __construct(DependencyContainer $di){
     $this->_db = $di->getDb();
  }
}

$dependencies = new DependencyContainer($someParams);
$user = new User($dependencies);

You must think you just another class and more complexity. But, your user class may need something to log messages like lot of other classes. Just add a getMessageHandler function to your dependency container, and some $this->_messages = $di->getMessageHandler() to your user class. Nothing to change in the rest of your code.

You'll get lot of infos on symfony's doc

Arkh