JasonDavis
JasonDavis

Reputation: 48933

Is this too many dependencies to inject into an object through the constructor?

I am working on a social network type project in OO PHP and I do not want to use an existing framework. The main point of doing this project is to help me learn about more stuff.

This question is more about dependency injection.

Let's say I have these classes:

core class - some core methods to do stuff in the app
config class - loads site config stuff
database class - connects to mysql and does all database related stuff
logger class - used to log errors and debug info
captcha class - for captcha on forms
session class - initiates a session start and adds, removes, gets session variables to use in the app
cache class - similar to session class but for caches items (files cache, memcache, apc cache. I may even add my session stuff to this class someday since all these cache's can use the same type of methods)

All the classes above will most likely be used on every page load in my app (I probably missed some more classes that will be added later on)

Now in addition to the above classes which will need to be injected into most other classes, I will have many many more classes. I will have a secion called modules which will have stuff like...

account class - creates new users, authenticates users, logs users in and out of the app, update user settings, and much more.
users class - shows users profiles, shows users online, new users, all stuff to show users of the site
forums class - will be for the forums section
blogs class - for the blogs section
photos class - all photo related stuff
comments class - handles comments for photos and profiles

There will be many more of these type of classes for different sections of the site.
This second set of classes listed above for sections will most likely require most of the classes from the first set to be injected into them.

So should I use a registry to store the objects from the first set of classes and just inject the registry into all the class objects in the second set of classes?

Or should I use the constructor to load them? In this example there would be like 7 objects to inject into the other classes, that seems like a lot. Am I going about this wrong?

---EDIT---
I am aware of the singleton pattern but I don't think it is my best option here

---EDIT 2---
As some have mention, needing to pass in as much as 7 objects does seem like a LOT and that is why I am looking for suggestions. Luckily for me this project is at the beginning stages so now is the time for changes to the structure.

An example would be a class in my forums section. The forums class would need access to session data, possible cached data, the configs object, database object. AM I going about this the wrong way?

Upvotes: 9

Views: 2188

Answers (2)

keithjgrant
keithjgrant

Reputation: 12739

Or should I use the constructor to load them? In this example there would be like 7 objects to inject into the other classes, that seems like a lot. Am I going about this wrong?

When you start needing to inject that many objects, you need to ask whether the object that receives them is responsible for too much. Can it be broken down into smaller pieces?

If it really can't, then consider encapsulating related objects in another class. Perhaps your session, logger, and config objects can be injected into an App or Application object?

Edit: I notice most of the other answers so far talk about Singletons. Note that Singletons are the enemy of DI. Great Google tech talk on this here.

Edit 2:

What I mean by encapsulating is, instead of injecting Session, Logger, Config, etc. all into your Account class, maybe they should be injected into an Application class, and an Application instance can be injected into Account.

To be honest, this is still a piece of DI I'm wrapping me head around, but what I'm starting to see is this: You should only inject into Account the objects it will directly need to manipulate. Those objects may need to manipulate yet other objects, but Account doesn't need to know about it.


Often, you'll find you don't even need as many "layers" as you thought, though. If you find you're injecting stuff all over the place, consider various ways of re-structuring your application. Let me pull a piece of code from the Pylons documentation on the model:

a = model.Person()
a.name = "Aaa"
a.email = "[email protected]"
meta.Session.add(a)

(Don't worry about meta.Session... basically it handles interaction with the database.)

Here, we instantiate a Person, set a couple of its attributes, and then save it. You'll notice the Person class knows nothing about the database, and in fact doesn't even have a save() method. Instead, we pass it to the database class (meta.Session) which saves it. We've separated concern for Person logic from the database code. meta.Session could work a dozen different ways, but as long as it knows how to read Person, we're fine. (in this case, during application initialization, it read the definition of all the application's models).


Okay, I'm going to sum up, because I've obviously rambled a lot here. There is no one "correct" answer to your question (as far as I know, but I don't proclaim to be a DI expert by any means).

Yes, injecting several objects is probably indication of some need to restructure, but you have a number of considerations to make:

  • Is the object receiving the injection responsible for too much; can it be separated out?
  • Are you only injecting objects that the recipient class will directly need to utilize?
  • Are you injecting the wrong direction; can your Account object be injected into your Database instead of the other way around?

Upvotes: 12

RobertPitt
RobertPitt

Reputation: 57268

I've always preferred the Registry approach.

Reasons:

  • Larger Scope
  • Simple to get
  • constructors are freed from having objects as variables (allows better usage)
  • Allows you use more objects in your classes as your free to grab what you need, when you want.

Although there is another method you can try and thats using the singleton pattern, where you would have a method in every class that keeps track of its own object.

Fors example, create an interface like so:

interface ISingleton
{
    public static getInstnace();
}

Then for every object you can add the method that is used for the getting of the instance.

class SomeObject implements ISingleton, ISomeThingElse
{
    private static $_instance;
    public static getInstance()
    {
        if(self::$_instance === null)
        {
           self::$_instance = new SomeObject(); 
        }
        return self::$_instance;
    }
}

This way your always keeping your same instance of the object as well as having a global scope.

Example:

public function GetUser($id)
{
    return Database::getInstance()->fetchUserById($id);
}

Hope this helps.


There is another way you can do and that's creating a context class, let me try and explain:

The class would act like a registry but disposable, for example:

class Context
{
    private $objects = array();

    public function Add($key,$Object)
    {
        $this->objects[$key] = $object;
    }

    public function __get($key)
    {
        return isset($this->objects[$key]) ? $this->objects[$key] : null;
    }
}

And use that as a container to hold your objects like so:

$Context = new Context();
$Context->Add("database",$database);
$Context->Add("logger",$logger);
$Context->Add("session",$session);

$UserObject = new RegularUser($Context);

This way you can group a set of objects and pass the same context into several other library objects.

Upvotes: -2

Related Questions