Laravel Facades – creating and deep understanding

single-image

Many people think that Laravel Facades are bad or difficult to understand. It is not like that at all. In this article I will show you how to create and understand Facades

Once, on one of Laravel’s Facebook groups, there was a discussion about Symfony’s advantage over Laravel. I read with amazement that one of the users stated that Facade is one of the elements for which people avoid Laravel. I completely don’t understand it because they are an absolutely optional tool. Secondly, they are the anti-pattern “Singleton” implementation.

This article will not be about Laravel’s superiority over Symfony, nor about why “Singleton” is considered by many to be anti-pattern rather than pattern.

Facades use anti-pattern Singleton

I believe that this is a key issue to understand the subject of Facade and what it should be used for. This can’t be simpler said so we have to remember it for now: Facades use anti-pattern Singleton!

What is Singleton? Let’s look at wikipedia:

In software engineering, the singleton pattern is a software design pattern that restricts the instantiation of a class to one “single” instance. This is useful when exactly one object is needed to coordinate actions across the system. The term comes from the mathematical concept of a singleton.

To understand this in practice, let’s look at the examples below.

Suppose we have one of the easiest to imagine ExampleService classes:

namespace App\Example;
class ExampleService
{
    public $field;
}

By default, most of us use “Automatic Injection” when using Dependency Injection, regardless of whether they are aware of it, because this is a desirable behavior for the absolute majority of implantation logic. Translating this into adding a simple bind to the Service Container we will get:

// app/Providers/AppServiceProvider.php
$this->app->bind(ExampleService::class, function ($app) {
    return new ExampleService();
});

Generally, we want to check how to call the ExampleService class in more than one class constructor. Of course, using the above code, we expect that in every constructor we will get a new instance of our ExampleService class because we do not use Singleton. Look at this example:

namespace App\Example;
class ExampleServiceConsumer
{
    public function __construct(ExampleService $exampleService)
    {
        $exampleService->field = 'foo';
    }
}
namespace App\Example;
class ExampleServiceSecondConsumer
{
    public function __construct(ExampleService $exampleService)
    {
        dd($exampleService);
    }
}
namespace App\Http\Controllers;
use App\Example\ExampleServiceConsumer;
use App\Example\ExampleServiceSecondConsumer;
class HomeController extends Controller
{
    public function home(ExampleServiceConsumer $consumer, ExampleServiceSecondConsumer $secondConsumer)
    {
    }
}

Try to think about result of using HomeController:

Result of using home function from HomeController

Migrating to Singleton

Without any change to the logic of the code, only a change in the AppServiceProvider from bind to singleton

// app/Providers/AppServiceProvider.php
$this->app->singleton(ExampleService::class, function ($app) {
    return new ExampleService();
});

Stop for a moment and think about the result. We present it below:

Result of using home function from HomeController

Creating Facades

Facades and their use do not have much in common with static functions. They use the magic __callStatic() method to resolve container and use classic DependencyInjection.

Suppose we have an equally simple TestService class:

namespace App\Example;
class TestService
{
    private $field;
    public function setField($field)
    {
        $this->field = $field;
    }
    public function getField()
    {
        return $this->field;
    }
}

To create the facade, we need a few fairly simple steps. The first is to create the TestServiceFacade class:

namespace App\Example;
use Illuminate\Support\Facades\Facade;
class TestServiceFacade extends Facade
{
    protected static function getFacadeAccessor()
    {
        return 'test';
    }
}

Then in AppServiceProvider (or any other) we add:

$this->app->bind('test', function () {
    return new TestService();
 });

To finally add an alias in app/config.php:

'aliases' => [
    // ...
    'Test' => App\Example\TestServiceFacade::class,
],

And thats it. You can use Facade now.

An example of using Singleton in Facades

Suppose we have two classes of Consumers of TestService:

namespace App\Example;
class TestServiceConsumer
{
    public function __construct()
    {
        \Test::setField('foo');
        dump(\Test::getField());
    }
}
namespace App\Example;
class TestServiceSecondConsumer
{
    public function __construct(ExampleService $exampleService)
    {
       dd(\Test::getField());
    }
}

We call them as follows:

namespace App\Http\Controllers;
use App\Example\TestServiceConsumer;
use App\Example\TestServiceSecondConsumer;
class HomeController extends Controller
{
    public function home(TestServiceConsumer $consumer, TestServiceSecondConsumer $secondConsumer)
    {
    }
}

And we check the result:

Result of using home() function in HomeController

Summary

There is no reason not to use Facades if you understand their operation, because they are an implementation of the Singleton pattern. In addition, they can be used in tests because Laravel provides functions for Mocking them.

In addition, keep in mind that there are people who say that Singleton should not be used in applications due to a number of disadvantages (mainly test), but about this next article.


Please leave me comment if you have any question. If you liked this post, go to my instagram and follow me to stay up to date!

You may like