Laravel 4 IoC – Bindings and the Application Instance

laravel 4 logoAt a recent business networking event I got talking to another web developer, who has just started using Laravel 4. We got chatting about Laravel in general and how awesome it is.Of course, the subject of IoC cropped up. The other developer commented on IoC, saying, “you need to be really careful with the IoC and passing an instance of the $app into the closure for performance reasons, the $app shouldn’t really be passed through at all ideally”. His argument also focused upon the fact that injecting the “Laravel 4 Facades” (config/app.php line 151) into controllers as it is faster.

Personally, I think he’d missed the point of IoC here. The only point he does have at a push, I assume, is if the object doesn’t need an instance of the $app, then don’t pass it through the closure – but that’s pretty obvious?

The following code is possible in a controller. Laravel would use PHP’s Reflection API to resolve the “Input” object and any dependencies. This is more of a typical DI approach and may seem more familiar:

// Some controller
protected $input;
public function __construct(Input $input)
{
 $this->input = $input;
}

That’s fine at a push and if using auto loaded aliased classes (Laravel has a list of these aliases at config/app.php (see: https://github.com/laravel/laravel/blob/master/app/config/app.php#L151). For me, this appraoch does place a a certain amount of responsibility on the framework and the availability of such classes – personally, the controller is more tightly coupled than I’d like it to be.

The usefulness of IoC comes when registering your own objects and associated dependencies, all of which could have dependencies themselves. This method provides more control, enabling easy viewing of how objects and their dependencies are instantiated.

It is common to see code as follows throughout the framework, within service provider – for good reason too:

// Some service provider
$this->app->bindShared('form', function($app)
{
 $form = new FormBuilder($app['html'], $app['url'], $app['session.store']->getToken());
 return $form->setSessionStore($app['session.store']);
});

We can see the class FormBuilder has several dependencies. Additionally, these dependencies have their own dependencies.

This is one of (the only?) reason an instance of “$app” is passed as an argument in the closure when registering bindings. So, using code like $app['html'] will inject an instance of the html class, with all dependencies for the Html class, into the FormBuilder class.

As for the performance hit referenced by the developer, personally, I’d be pushed to prove this. I’d imagine the hit would be negligible.

The first line of code in bootstrap/start.php registers the $app object very early on in each request:

// bootstrap/start.php
$app = new Illuminate\Foundation\Application;

Without this binding, instantiating code like below, where an object has several injected dependencies would quickly become a pain:

// some service provider
public function register()
{
   $this->app->bind('foo', function($app)
   {
     return new Foo($app['config'], $app['request'], $app['bar']);
   });
}

This is much better than manually creating a $foo object whenever required by the application:

// some controller
protected $foo;
public function __construct()
{
 $this->foo = new Foo(new Config, new Request(new Url), new Bar(new Storage));
}

If the code to create a foo object was to change I’d need to go through the whole application and manually make a change. For arguments sake, say the request class now depended upon a Session object instead. If registering such bindings via a service provider and make use of the application container, Laravel does this for us automatically.

This turned into a bit of an unorganised rant towards the end, thanks for hanging in there 🙂

Published by

Rob Allport

Web Developer based in Stoke-on-Trent Staffordshire Google+ - Twitter

Leave a Reply

Your email address will not be published. Required fields are marked *