How to change this code to remove hard-coded dependency

I have some code like so:

class MyClass
{
    public function maybeDoSomething(maybe)
    {
        if (maybe) {
            $this->_doSomething();
        }
    }
    
    protected function _doSomething()
    {
        $something = Something::getInstance();
        $something->do();
    }
}

There are a couple of problems here I’d like to fix - the hard-coded dependency and the use of a singleton class.

One solution would be to use a dependency injection container, which would solve both problems (The Something class could be changed to a standard class and the container would ensure only a single instance is created).

class MyClass
{
    public function __construct(ISomething $something)
    {
        $this->_something = $something;
    }
    
    public function maybeDoSomething(maybe)
    {
        if (maybe) {
            $this->_doSomething();
        }
    }
    
    protected function _doSomething()
    {
        $this->_something->do();
    }
}

However, I don’t know how you could do that without the container creating an instance of Something, even though it may not be needed. I’d like to avoid instantiating objects that aren’t used.

Another option would be a dependency suction container (for want of a better term) that is passed into MyClass. Then when _doSomething() is called, it gets the dependency from the container.

class MyClass
{
    public function __construct(Container $container)
    {
        $this->_registry = $container;
    }
    
    public function maybeDoSomething(maybe)
    {
        if (maybe) {
            $this->_doSomething();
        }
    }
    
    protected function _doSomething()
    {
        $this->_registry->get('ISomething')->do();
    }
}

That ensures that the Something class would only be instantiated when needed, but adds another dependency to the class and seems rather messy.

Anyone have a better idea?

1 Like

The Symfony dependency injection container has the notion of a lazy service: http://symfony.com/doc/current/components/dependency_injection/lazy_services.html

It is basically a proxy which automatically creates the real service the first time you use it.

You could also inject a light weight factory and again just create the service when actually needed.

But this is really only for objects with heavy constructors. Most of the time the overhead of creating an unused object will not even be noticeable.

3 Likes

Thanks for that. I did think of modifying MyClass so that Something could be set as a closure to be instantiated when needed or an instance, but it would be rather messy. Doing that via a container makes much more sense. I’ll have to take a look at how that Symfony class works in more detail.

Injecting a factory is a similar thing to what I meant by using a dependency suction container. While it does solve the problem, it introduces an extra dependency on the factory class.

I agree it’s only worthwhile for heavy objects, and even then it’s probably only worthwhile if there’s a good chance the object won’t be needed.

Thanks again for the help.

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.