14

I am refactoring a PHP application, and I am trying to do has much dependency injection (DI) as possible.

I feel like I've got a good grasp of how it works, and I can certainly see my classes becoming a lot leaner and more robust.

I'm refactoring so that I can inject a dependency rather than create a new object within the class, but at some point I am going to have to create some objects, that is, use the dreaded new keyword.

The problem I have now run into is at what point can I actually create new objects? It's looking like I'll end up at a top level class, creating loads of new objects as there is no where else to go. This feels wrong.

I've read some blogs that use factory classes to create all the objects, and then you inject the factory into other classes. You can then call the factory methods, and the factory creates the new object for you.

My concern with doing this is now my factory classes are going to be a new free-for-all! I guess this may be OK as they are factory classes, but are there some rules to stick to when using a factory pattern and DI, or am I going way off the mark here?

Peter Mortensen
  • 1,050
  • 2
  • 12
  • 14
GWed
  • 3,085
  • 5
  • 26
  • 43
  • Related: [Why is Inversion of Control named that way?](http://programmers.stackexchange.com/a/205685) – Robert Harvey Oct 31 '13 at 20:10
  • I recommend IoC for services and policies. For model or helper classes I'd simply use `new`. Of course there are a few entry points where you need to call into the IoC container, but there shouldn't be many. Typically you configure the IoC once and then ask for one class to be resolved per request. In the case of MVC that's typically the controller. – CodesInChaos Nov 01 '13 at 09:57
  • The top level class you mention is part of the Composition Root. It is far from wrong. – Facio Ratio Nov 06 '13 at 01:43

3 Answers3

13

After quite a bit of googling around for this, it seems like (as mentioned in a comment above) the top level class I was talking about is called the Composition Root.

It does indeed seem to be the accepted solution to add the creation of all objects within this Composition Root (or referencing an IoC container from here).

My original concern with this was that this top level class would end up being a bit of a mess. This is true to some extent, but the pros out weigh the cons. For example I can see the readability, testability and maintainability of all my other classes has improved.

The top level class may be a bit messy, littered with new and set_property() but I have to say I actually prefer having all this code in one place, rather than scattered about all over the other classes

Another useful page discussing performance hits of this method here

James
  • 243
  • 1
  • 16
GWed
  • 3,085
  • 5
  • 26
  • 43
3

A Factory class will have new sprinkled throughout it. It would be creating whatever object that you are requesting and probably the dependencies of that object. Since the factories job is to instantiate the correct object for you having new in this class isn't a bad thing.

DI is so that you have a loosely-coupled design. You are able to make changes to your application by changing the dependency that is provided to each object. Making your application flexible, extensible and easy to test.

At the top level, you will have code that will instantiate a couple of factories, setup connections to services, and send a response. It will have a fair amount of new or static calls to instantiate objects that are necessary for your application. That would be where that belongs.

Schleis
  • 3,376
  • 1
  • 19
  • 21
-2

My two cents here:

I am refactoring a php application and I am trying to do has much dependency injection as possible

You don't state if you are using a dependency injection framework. I think you definitely should. Use something that gives you the features you need: https://stackoverflow.com/questions/9348376/guice-like-dependency-injection-frameworks-in-php .

The problem I have now run into is at what point can I actually create new objects? Its looking like I'll end up at a top level class, creating loads of new objects as there is no where else to go. This feels wrong.

You normally use configuration or a central point for the instantiation of the initial objects that compose your application. The container will create the objects for you.

You then access objects (services, providers, controllers...) via the IoC container. It will transparently create an object for you if needed, or give you a reference to the appropriate existing instance.

Of course, inside your particular implementation of objects you can instantiate other objects on which you don't need DI (data structures, custom types, etc), but that's normal programming.

I've read some blogs that use factory classes to create all the objects, and then you inject the factory into other classes. You can then call the factory methods, and the factory creates the new object for you.

Normally, you use a Factory if you want the IoC framework to instantiate some IoC objects through your factories (this is needed when instantiating a particular object requires some extra work). If you can simply create your objects with "new Object()", and setting some properties, you don't necessarily want to use a Factory pattern.

In other words, I'd say that using a Factory pattern for a class or group of classes depends on how you want to model those classes, not on whether you use DI (unless your DI implementation explicitly requires factories, which is unusual).

You also configure your IoC framework to use a Factory when you are using a 3rd party lib that already requires the usage of a Factory. In this case you have no control about this and you need to tell your IoC container: "hey, when I ask for one of these interfaces, you have to use this factory to provide me with an appropriate instance".

My concern with doing this is now my factory classes are going to be a new free-for-all! I guess this may be ok as they are factory classes, but are there some rules to stick to when using factory pattern and DI, or am I going way off the mark here.

In this case, it sounds that you don't need to use Factory patterns for these objects/services/controllers/whatever, and you can simply configure your IoC to instantiate with "new" the appropriate class and inject everything else.

I hope it helps.

jjmontes
  • 138
  • 6
  • thanks for answer, but surely the IoC container is the 'top level class' i was referring to. If I can only create objects in there, it's going to be a right mess. – GWed Oct 31 '13 at 18:32
  • 4
    `doing DI manually beats the whole purpose of using an Inversion of Control container` -- If by that you mean *"...which is centralizing your dependencies in a configuration file"* then you're right, because that's all an IoC container really does. The real goal of DI is decoupling, and you can do that by supplying your dependencies in a constructor method. You don't need a DI framework at all to do that. – Robert Harvey Oct 31 '13 at 18:34
  • mmm you don't create objects, you ask the IoC container for them (from anywhere you need to), or you use field/argument injection so your classes are automagically injected the appropriate classes, created always by the IoC container. – jjmontes Oct 31 '13 at 18:34
  • @RobertHarvey: I meant something more like "...which is having clearer, more maintenable, and decoupled code". I still think that reinventing the wheel is not the way to go. Simply passing a constructor to your dependencies will make a their implementation a mess, and you miss all the nice features like field injection (and provided your dependencies are under your control, which they don't have to). Also, note the OP asks for DI, not IoC, and so imho it holds true that doing DI manually today is probably unnnecessary, and you do need a framework. – jjmontes Oct 31 '13 at 18:39
  • :-S confused... – GWed Oct 31 '13 at 18:41
  • 1
    I would agree that you need a framework for *very large* applications. Many applications are not that large, and do not benefit from the additional complexity of using a DI framework. – Robert Harvey Oct 31 '13 at 18:48
  • @Gaz_Edge: Try to read this page thoroughly, contains a before-IoC and an after-IoC example: https://github.com/stubbles/stubbles-core/wiki/Introduction – jjmontes Oct 31 '13 at 18:49
  • @RobertHarvey: Imho, that's what the OP asked for. That's how DI works: you ask the framework (the "binder", in that example) for the instance you need, if I'm right. The size of the application was not the subject of the question. – jjmontes Oct 31 '13 at 18:55
  • 2
    I didn't say that it was. I simply said that you don't need a DI container to do it. – Robert Harvey Oct 31 '13 at 18:56