jon
jon

Reputation: 1581

PHP - if autoloading, why would you use dependancy injection?

Please forgive the possible naivety of this question, however I am getting myself really confused. It appears that it is good practice to use dependancy injection to decouple your code so that your classes are loaded with their dependancies. PLease imagine the following where Class Foo has a dependancy of class Bar

namespace Classes;

class Foo{

    protected barInstance;

    public function __construct(Bar $barInstance){
        $this->barInstance=$barInstance;
    }

}

However if you are autoloading your classes then surely the following does the exact same thing without the need of DI?

namespace Classes;
use Classes/Bar;

class Foo{

    protected barInstance;

    public function __construct(){
        $this->barInstance=new Bar;
    }

}

Thanks to any responders.

Upvotes: 3

Views: 1536

Answers (4)

Matt S
Matt S

Reputation: 15364

Autoloading ensures your class is defined when you reference it. Dependency injection gives you flexibility over what instance of an object you use.

In your example, lets say your Bar class manages a database connection. And lets say you sometimes want to connect to a different database.

public function __construct(){
    $this->barInstance = new Bar();
}

Now you must refactor your Foo class to handle the change because you've tightly coupled it with an instance of Bar.

public function __construct(Bar $barInstance){
    $this->barInstance = $barInstance;
}

Now, without changing Foo, I can instantiate a different instance of Bar for different situations. A commonly useful example of this is in unit tests.

In both cases autoloading made sure that Bar and all of its own dependencies are are defined outside of Foo.

Upvotes: 3

olibiaz
olibiaz

Reputation: 2595

Take the example with a database connection.

you have

public class foo {
    public function __construct(DbConnectionInterface $db) { ... }
}

public class foo2 { 
    public function __construct(DbConnectionInterface $db) { ... }
}

...

and so on

In your "service container" you have something like that

$db = new PdoDbConnection(); // which implements DbConnectionInterface

$service['foo'] = new foo($db);
$service['foo2'] = new foo2($db);

If tomorrow you want to use something else than pdo, then you just have to make a new connection implementing the interface and then you can change your db connection in one place

$db = new NotPdoDbConnection(); // which implements DbConnectionInterface

$service['foo'] = new foo($db);
$service['foo2'] = new foo2($db);

If you didn't use the DI, then you should have changed your new PdoConnection() to new NotPdoConnection() in all the classes using this class. But the autoload cannot help you some much in this case. As said by lsklyut his answer its two different concepts.

its a "dummy" case but you can read some interesting articles about DI

http://fabien.potencier.org/what-is-dependency-injection.html http://www.martinfowler.com/articles/injection.html

Upvotes: 2

axiac
axiac

Reputation: 72177

Autoloading and dependency injection are unrelated concepts.

The autoloader knows how to load the classes. When a simple statement like new Foo() runs, the interpreter needs to know the definition of the Foo class. If it doesn't already know it then it invokes the autoloader(s) until the class becomes available. The autoloaders know where each class is defined and include the correct file.

The dependency injection container knows how to build objects of various types. It doesn't know (and doesn't care) about class loading. It assumes that when it runs new Bar() the class Bar is already defined (or it can be autoloaded).

Upvotes: 0

lsklyut
lsklyut

Reputation: 396

These are two separate concepts. Autoloading will allow you to not have to include files in your scripts and allow you to separate your classes by concept. As far as dependency injection, if Bar had additional dependencies and could not simply be instantiated by using new Bar(), but rather new Bar($dep1, $dep2), then your logic to create Bar would be buried inside Foo's constructor, as well as the constructor of any other class which requires Bar. By inverting the dependency creating Bar somewhere else before injecting it, you're relieving Foo of that additional responsibility.

Upvotes: 0

Related Questions