Back to Course |
Design Patterns in Laravel 11

Facades: They Are Everywhere in Laravel

Have you ever used Auth::user() in Laravel? So yeah, that Auth is a Facade. Now, we will explore what ready-made Laravel Facades are and how/why we should create our own Facades.


What are Facades?

First, the definition.

Laravel documentation about Facades is, well, a bit confusing:

Laravel Facades serve as "static proxies" to underlying classes in the service container, providing the benefit of a terse, expressive syntax while maintaining more testability and flexibility than traditional static methods.

Wait, what does that mean in human language?

Well, you won't have to know what class is underneath the Facade. You can just call the Auth facade and access methods from the underlying class.


Laravel Facades We Can Use

In Laravel, we can call Auth::user() to retrieve the user from the session.

What we don't see under the hood is that it is a "static proxy" to the Illuminate\Auth\AuthManager class. The AuthManager class has a user() method that returns the user from the session.

Facade makes our experience as developers easier. We only have to remember the Auth Facade, and we get instant static access to the user() method.

Let's quickly compare facade usage with the usage of the class itself to illustrate the difference.

How would it look without Facades?

Creating New Class Instance

use Illuminate\Auth\AuthManager;
 
public function index()
{
$auth = new AuthManager();
$user = $auth->user();
}

Or, a bit shorter, with Dependency Injection.

Using Dependency Injection

use Illuminate\Auth\AuthManager;
 
public function index(AuthManager $auth)
{
$user = $auth->user();
}

With the Facade under the hood, it's just one line.

Using Facade

public function index()
{
$user = Auth::user();
}

So, in short, Facade is just like a shortcut to a specific class.

Now that we know what they are let's think about whether we need to use them and how.

First, it's convenient to use the Facades from Laravel core:

Also, package creators use Facades. It's easier to remember the Facade's name than the complete class's name.

spatie/laravel-activitylog:

use Spatie\Activitylog\Facades\LogBatch;
 
// ...
 
LogBatch::startBatch();

barryvdh/laravel-debugbar:

// In AppServiceProvider:
public function register(): void
{
$loader = \Illuminate\Foundation\AliasLoader::getInstance();
$loader->alias('Debugbar', \Barryvdh\Debugbar\Facades\Debugbar::class);
}
 
// ... then, anywhere:
 
Debugbar::info($object);
Debugbar::error('Error!');
Debugbar::warning('Watch out…');
Debugbar::addMessage('Another message', 'mylabel');

Creating Your Own Facades: Not So Great

For example, imagine that you have a Service class called SearchService that has a method called get():

app/Services/SearchService.php

namespace App\Services\SearchService;
 
class SearchService
{
public function get(string $query): array
{
// ...
}
}

To create a "shortcut" to it, you create a Facade called Search:

app/Facades/Search.php

namespace App\Services\Facades;
 
use Illuminate\Support\Facades\Facade;
 
class Search extends Facade
{
protected static function getFacadeAccessor()
{
return \App\Services\SearchService::class;
}
}

So now you can use Search::get().

Great, right?

Not really. You lose auto-complete in your IDE. When you use Facades, you don't have access to the methods available in the class. Your IDE might not show that the class exists or that it doesn't have any methods!

And that's true, because your Facade class doesn't have the get() method in it.

You can make the IDE autocomplete work by adding doc blocks to the Facade class:

app/Facades/Search.php

namespace App\Services\Facades;
 
/**
* @method static get(string $query)
*/
class Search extends Facade {
// ...
}

But you'll also have to manage another file to ensure that all methods are added to the Facade. This seems complicated to me.


Facades Can Override The Names of Classes

Another flexibility but also a downside, in my opinion.

When creating a Facade, you don't have to follow the same Class name you intend to call.

This means I can use whatever name I want for the Facade, which will still work. Let's look at an example:

Creating a Facade

class MyRandomClassName extends Facade
{
protected static function getFacadeAccessor()
{
return \App\Services\SearchService::class;
}
}

config/app.php

// ...
'aliases' => Facade::defaultAliases()->merge([
// ...
'MyRandomClassName' => \App\Services\Facades\MyRandomClassName::class,
])->toArray(),

Facade Usage

\MyRandomClassName::get('query');

Now, I can use the MyRandomClassName facade to call the Search class. No imports are needed, as you can access it globally.

Even worse is the fact that this class might not even exist! How? Well, we are creating an alias. Let's change the config a bit:

config/app.php

// ...
'aliases' => Facade::defaultAliases()->merge([
// ...
'MadeUpAlias' => \App\Services\Facades\MyRandomClassName::class,
])->toArray(),

Facade Usage

\MadeUpAlias::get('query');

This will still work! But if you try to search globally for MadeUpAlias, there will be no results.

This is because it's not a real class. It's just an alias for a class that exists.

So, I'd say that Facades are convenient and easy to use, from framework and packages. But if we try creating your Facades, you have to really know what you are doing.


Next: Repository Pattern?

The following lesson will be pretty interesting. The repository pattern was very popular in the times of Laravel 4, but recently, very few developers have used it in practice. I will explain why.