Laravel: The magic of “build()”

Just an easy snippet you should take into consideration when building something.

The Service Container is very simple yet powerful tool in your Laravel app. Most of the time is associated to the Service Provider, where you usually bind a Class, sometimes as a singleton (single instance), inside the container so later can be retrieved and used by multiple services.

The point of the Service Container is to instantiate a class which depends on others, automatically, by just hinting the interface they use. But what about doing just that without saving it into the Service Container?

In this example I will create a class that will write something into the Cache. Since we don’t know what Cache is using your app by default, we can just ask for any Cache implementation using the Repository contract.

<?php

namespace App;

use Illuminate\Contracts\Cache\Store as Cache;

class SaveSomethingTemporarily
{

/**
* The Cache Store
*
*
@var Cache
*/
private $cache;

/**
* SaveSomethingTemporarily constructor.
*
*
@param Cache $cache
*/
public function __construct(Cache $cache)
{
$this->cache = $cache;
}

/**
* Saves a String for 10 minutes
*
*
@param string $string
*/
public function saveStringForTenMinutes(string $string)
{
$this->cache->put('scratch', $string, 10);
}

}

Now comes the problem. How we can instantiate this class, using the Service Container to inject its dependencies? Thankfully, there is a very simple way to do it:

<?php

namespace App\Http\Controllers;

use App\SaveSomethingTemporarily;

class SaveController extends Controller
{

/**
* Saves a String for 10 minutes
*
*
@param string $string
*
@throws \Illuminate\Contracts\Container\BindingResolutionException
*/
public function saveString(string $string)
{
app()->build(SaveSomethingTemporarily::class)
->saveStringForTenMinutes($string);
}

}

Using app()->build(ConcreteClass::class) will instruct the Service Container to create a new instance of that particular class. It will check what its constructor requires, fetch (or make) thay dependency and return the instance.

This avoids some simple problems:

  • Manually instantiating the Class and injecting every dependency manually.
  • Using Facades or app(Dependency::class) inside the constructor.
  • Persisting it inside the Service Container unnecessarily for the rest of the application cycle.

And just by that you can have your class with its dependencies set.

If you need some fine tuning, you can use app()->make(Concrete::class, [$parameter]).