0

For example, my DependentClass depends on some AbstractCsv class. Here is the declaration of AbstractCsv's factory (http://csv.thephpleague.com/instantiation/):

public static AbstractCsv::createFromFileObject(SplFileObject $obj): AbstractCsv

And here is the declaration of DependentClass's constructor:

class DependentClass {
    public function __construct(AbstractCsv $csv) { /* implementation... */ }
    // implementation...
}

As you can see, to instantiate AbstractCsv, I need to pass in an instance of SplFileObject to dependency's factory function AbstractCsv::createFromFileObject. To create an SplFileObject, I need a filename. DependentClass stores the filename needed (or, for example, the filename is calculated dynamically within DependentClass at runtime).

How can I pass an instance of AbstractCsv into the DependentClass's constructor, if:

  • the filename is defined inside the DependentClass itself,
  • and also to create an instance of AbstractCsv, I first have to create an SplFileObject and then an AbstactCsv? It is a vicious circle!

I currently see the only solution to break this circle: DependentClass should not depend on AbstractCsv, but on its factory which will provide an instance of AbstractCsv to DependentClass on-demand. This also will eliminate the need to create SplFileObject within the DependentClass:

class DependentClass {
    public function __construct(CsvProvider $csvProvider) { /* implementation... */ }
    // implementation...
    public function someMethod($value) {
        $filename = rand($value); // somehow calculate $filename
        $csvFile = $this->csvProvider($filename);
        $csvFile->fwrite($someData);
    }
}

class CsvProvider {
    public function get(string $filename) : AbstractCsv {
        return AbstractCsv::createFromFileObject(new SplFileObject($filename));
    }
}

I think, this problem is common and occurs very often, right? I'm currently new to DI, so I wonder: is this solution really the right way to solve this problem? And what's the name of such factories? I called it provider. Is it a correct term for this?

Anatoly U
  • 258
  • 1
  • 11
  • Where the dependent class gets the filename? Can it be passed to the constructor as well? – neochief Apr 18 '16 at 08:25
  • No, it cannot. For example, the generation of filename is a part of business logic within the dependent class. Sometimes it happens, that some information needed to create the dependency is inside the dependent class. What to do in such cases to follow the DI pattern? – Anatoly U Apr 18 '16 at 19:14
  • Yeah, then I think your approach is fine. – neochief Apr 19 '16 at 08:53
  • How often do similar situations occur? Is it OK, or it is a code smell, and do other solutions of this problem exist? How often does it happen that some business logic class produces some data, on which some classes depend, and therefore the DI container cannot inject those dependent classes? – Anatoly U Apr 19 '16 at 19:36

0 Answers0