0

I have a class which has a number of dependencies. Currently these are set in the constructor:

class Thing
{
    public function __construct()
    {
        $this->dependencyA = new DependencyA();
        $this->dependencyB = new DependencyB();
        $this->dependencyC = new DependencyC($this);
        $this->dependencyD = new DependencyD($this);
    }        
}

This is badly designed in terms of IoC and DI so I want to redesign this so that my dependencies are present in the constructor.

public class Thing
{
    public function __construct(
        $dependencyA, $dependencyB, $dependencyC, $dependencyD)
    {
        $this->dependencyA = $dependencyA;
        $this->dependencyB = $dependencyB;
        $this->dependencyC = $dependencyC;
        $this->dependencyC->setThing($this);
        $this->dependencyD = $dependencyD;
        $this->dependencyD->setThing($this);
     }
}

This makes things a lot easier to test however I do not want clients to have to instantiate all the dependencies. They are strictly internal classes for the Thing. Would this be a good candidate for a Static Factory as proposed below? This does however change how the dependencies that require Thing as a dependency are to be instantiated (i.e I have to set the dependency via a setter rather than a constructor) which I'm a little uncomfortable with. My proposed solution is below. Are there better approaches?

private class Thing
{
    public function __construct(
        $dependencyA, $dependencyB, $dependencyC, $dependencyD)
    {
        $this->dependencyA = $dependencyA;
        $this->dependencyB = $dependencyB;
        $this->dependencyC = $dependencyC;
        $this->setThing($this);
        $this->dependencyD = $dependencyD;
        $this->setThing($this);
    }

    public static function createThing()
    {
        return new Thing(
            new DependencyA(),
            new DependencyB(),
            new DependencyC(),
            new DependencyD());
}
Steven
  • 166,672
  • 24
  • 332
  • 435
Zakalwe
  • 1,444
  • 3
  • 14
  • 25
  • You seem to be creating a reusable library. Take a look that [this](https://blog.ploeh.dk/2014/05/19/di-friendly-library/) article by Mark Seemann that talks explicitly about creating DI-friendly libraries. The article is written in the context of .NET, but might be applicable to PHP as well. – Steven Jul 11 '21 at 19:33
  • Thank you. That's given me some food for thought. The actual implementation seems to adhere more to a Facade in reality (which was I was going to query in the question but really wasn't sure). All my methods make use of other classes to perform their function. I think also, I'll be able to refactor dependenices set via `setThing($thing)` making it cleaner. Sadly constructor chaining isn't possible with php but I like this idea. Overloading in general isn't possible. – Zakalwe Jul 12 '21 at 09:41
  • IoC is popular for obvious reasons, but I think people forget that dependencies are only bad if the thing(s) you depend on can (or tend to) change. MVC decouples views from Models because Views are more volatile than Models (generally). [Static factory](https://stackoverflow.com/a/929273/1168342) is good for encapsulating object creation. In your final Thing example, you haven't really avoided the direct dependency (it's just been moved to `createThing`). DI and encapsulating logic for object creation are separate problems. – Fuhrmanator Jul 14 '21 at 13:29

0 Answers0