Service needed only conditionally, how to without direct access to DIC?

Hey there,

I’m trying out Slim 3 since a few days, and although I’m deeply intrigued, I must say it’s been pretty tough to wrap my head around some of its concepts, mainly how to implement Dependency Injection strictly (which is a much more general topic than Slim 3, I know).

The problem at hand:

In this case I have a service (the default Slim PHP view renderer), that depends on another service (a Textile parser) only if a certain condition is met. The “parse” attribute is a closure that I’m attaching to the renderer because I want it to be available in views at all times.

// Textile HTML parser
$container['parser' ] = function($c) {
	return new \Netcarver\Textile\Parser( 'html5' );
});

// Slim's PHP views renderer
$container['renderer'] = function ($c) {
    $path = $c->settings['renderer']['template_path'];
    $renderer = new \Slim\Views\PhpRenderer( $path );
    $parser = $c->parser;
        
    $renderer->addAttribute( 'parse', function( $snippet ) use ($parser, $path ) {
    		
    		//snippet cacher
    		$cached = $path."snippets/html_cache/$snippet.php";
    		$source = $path."snippets/$snippet.textile";
    		
    		if ( ! file_exists( $cached ) or ( filemtime( $source ) > filemtime( $cached ) ) )
    		{
    			file_put_contents( $cached, $parser->textileThis( file_get_contents( $source ) ) );
    		}
    		
    		return file_get_contents( $cached );
    		
    	});
    return $renderer;
};

As you can see, I’m “injecting” (sort of, but maybe here’s where I’m going wrong) the parser into the closure. But this is not good: the parser gets instantiated at all times (expensive), even when it’s not needed. How would I handle this without direct access to the DIC, where the parser lives? Because that would be the lazy way: just pass the DIC into the closure and get the parser from it only when there’s no cached snippet.

I’d love to hear how to approach this issue in a strict DI manner without instantiating the parser unnecessarily.

So why you are not passing $c into your addAttribute closure and not accessing parser only when it’s needed?

Thanks for the suggestion, that’s exactly how I’ve patched things now. But passing the DIC around like that is considered bad practice in a Dependency Injection pattern, so I’m looking for “the right way” to do this.

It’s not bad practice while you building it. It would be if you would use it like that inside service.

It’s not bad practice while you building it. It would be if you would use it like that inside service.

I’m not so sure about that. If I just pass in the container, I’m making my ‘service’ dependent on the container. Isn’t that exactly what Dependency Injection tries to avoid?

From the comments underneath this article I learned the following:

Requesting services from the DIC in your classes is not an ideal way to do DI. doing this introduces a dependency on the DIC which is a problem for several reasons. It means that all classes requesting that object from the DIC will get the same object so you lose the ability to inject different implementations into different objects. It also means that your code cannot be used without the DIC or with an alternative DIC. Additionally in tests you need to use the DIC or mock it. Additionally your code cannot be used without the DIC or with an alternative DIC.

And:

When first encountering a DIC, many people think about injecting it into their Controller and simply replacing ‘new’ calls with calls to the DIC. Because, after all, the Controller’s job is to take runtime data and route it to other objects to process. But this is bad practice. Your Controller should only be aware of the actual objects it needs to interact with to do its job. It should not reach through the DIC to get those objects.

As I’m finding out, adopting this pattern is not as easy as it sounds. I want to use it in my current project, just to find out if it suits me. Be aware that there are strong opponents to the DI pattern too: Dependency Injection is Evil

I’m not so sure about that. If I just pass in the container, I’m making my ‘service’ dependent on the container. Isn’t that exactly what Dependency Injection tries to avoid?

Well the container is called a Dependency Injection Container… so no.

The DIC is responsible for managing instances to your dependencies.

Dependency injection is a much more broad concept that has to do with how you construct your objects in your project.

Example:

If Class A requires class B and C…

There are 2 ways to construct the object with Dependency injection.

  • Construction injection. new ClassA(Class B, Class c)
  • Setter Injection. new ClassA(); setB(ClassB); setC(Class c);

The DIC container is extremely useful because when you use instance factories you only end up creating the instances of objects you need and you do not waste any CPU cycles creating objects you do not need.

Setter injection is the best way to go if you have optional dependencies. Like Route B on controller A requires D,E… by Route C on Controller A requires F,G. Using Constructor injection you would need to inject all of them even though you are using only 2.

As for the proponents for hating DI… they are crazy. DI is literally the only way to use services from another class without coupling your objects together, so I just assume they have no idea what they are really talking about. Coupling is evil. DI also makes your code highly testable. Coupling makes your code not testable.

So i suppose if you don’t care about testable non coupled code, you can do silly stuff like…

Method B requires A,C,D E objects and a bunch of data.

gelggleto writes:

Well the container is called a Dependency Injection Container… so no.

I fail see how your explanation of the DI pattern makes it obvious that it’s no problem to pass the DIC far down into the dependency hierarchy.

From all the articles I’ve read on the subject so far, one of the most essential points of DI is to pass in dependencies as high up in the hierarchy as possible. Passing the DIC further down make all the descending layers dependent on the DIC itself, which is obviously a bad thing. Please read the two quotes in my reply to dopesong if you want to know why.

Injecting dependencies through the creator or setter method has no influence on the problem at hand: I only know if I need a certain dependency further down the hierarchy in an if-then statement. The only option is to inject it, always. But that would be very wasteful. In this case, I “solved” it by applying the YAGNI principle, but that’s really just an easy way out.

Although extremely simple, Rob Allen’s Slim Skeleton project shows exactly how to do proper DI. His “Actions” (controllers) factories are registered as a service, and when they instantiate the Action object, the dependencies get injected. And that’s about it.