Search code examples
phpinterfacedependency-injectiondecoupling

Dependency Injection - Is it better to pass a complete class, or the name of a class?


For dependency injection, I understand that I have to pass an instance of one class to the main instance instead of the main class creating it's own instance, like so (php):

class Class_One {
  protected $_other;
  public function setOtherClass( An_Interface $other_class ) {
    $this->_other_class = $other_class;
  }
  public function doWhateverYouHaveToDoWithTheOtherClass() {
    $this->_other_class->doYourThing();
  }
}

interface An_Interface {
  public function doYourThing();
}

class Class_Two implements An_Interface {
    public function doYourThing() { }
}

class Class_Three implements An_Interface {
    public function doYourThing() { }
}


// Implementation:
$class_one = new Class_One();
$class_two = new Class_Two();
$class_three = new Class_Three();
$class_one->setOtherClass( $class_two );
$class_one->doWhateverYouHaveToDoWithTheOtherClass();
$class_one->setOtherClass( $class_three );
$class_one->doWhateverYouHaveToDoWithTheOtherClass();

This is all fine. I know that since both Class_Two and Class_Three both implement An_Interface, they can be used interchangeably in Class_One. Class_One wouldn't know the difference between them.

My question is, is it ever a good idea to, instead of passing an instance to setOtherClass, pass a string such as "Class_Two", and have Class_One's setOtherClass method actually create the instance itself like so:

class Class_One {
  ...
  public function setOtherClass( $other_class_name ) {
    $this->_other_class = new $other_class_name();
  }
  ...
}

Does this sort of defeat the purpose of Dependency Injection, or is this completely valid? I thought this type of set up may help me with configuration, where a user can specify which class he wants to use in a string earlier on and this can later be passed to the Class_One..

Actually, writing this out has made me think that it's probably not a good solution, but I'll still post this in case someone can give me some good feedback on why I should/shouldn't do this.

Thanks =)

Ryan


Solution

  • That theoretically defeats the purpose of dependency injection; you are telling Class_One, which depends on An_Interface, which concrete implementation of that interface it should instantiate. That requires Class_One to know how to instantiate ANY An_Interface implementation, tightly coupling Class_One to ALL An_Interface implementations. If you add a new An_Interface Class_Four, you have to go back and tell Class_One how to instantiate a Class_Four.

    In PHP, you get away with this AS LONG AS all An_Interface implementations have a parameterless constructor. However, if any implementation needs OTHER dependencies injected, you're screwed; you can't tell Class_One to just new up a Class_Four if a Class_Four needs a Class_Five that Class_One doesn't know about.