Dependency Injection via Constructor vs Setter

dependency-injectionlaravel

UPDATE 2017/04/19

Another view is using wrappers for late binding.

Introduction

I believe that objects should be immutable, so I only set properties via the constructor. In that case, the object state never change.

Problem

There are cases the required parameters for the constructor aren't known at that moment. So I need:

  • a setter (not my preference)
  • a 'hard coded' instance in my method (no Depency Injection, not flexible) (not my preference)
  • a deferred binding (possible solution, but the disadvantage (I think) is that the container contains too many logic)

Case

Let me give a simplified code example to illustrate my problem (PHP).

interface Personable
{
    public function __toString();
}

final class Person implements Personable
{
    private $name;

    public function __construct(string $name)
    {
        $this->name = $name;
    }

    public function __toString(): string
    {
        return 'Person ' . $this->name;
    }
}

final class Foo
{
    private $personable;

    public function __construct(Personable $personable)
    {
        $this->personable = $personable;
    }
}

Question

Let's say that I default bind Personable to Person in my container. At that moment I haven't the required name parameter. I want to pass the instance of Person via constructor. What's the best practice?

Best Answer

I think that your Foo class should not depend on a Personable instance. Your Foo class probably has a number of methods that you can call to make it perform some actions using the Personable object, however I would argue that objects like Personable should be passed as an argument to those functions.

Class Foo
{
    public function printName(Personable $personable) 
    {
        echo (string)$personable;
    } 
} 

Try to inject stateless dependencies (services, repositories, factories, etc.) via the constructor and inject these stateful objects (database models and such) via the function that you are calling.