A Facade is a name given to a type of class in the Laravel framework that enables beginner-friendly and/or aesthetically pleasing access to tools and services held within the framework’s IoC container.
Here’s a quick example of a database query in Laravel.
<?php
DB::table('users')->get();
In the above example, we use Laravel’s fluent database abstraction layer (DBAL) to retrieve user data from the ‘users’ table of the database. It’s nice and simple. In this example, the DB
is the facade. We’re calling the table()
static method on the DB
facade, and later chaining a call to get()
to fetch the result.
A lot of people shy away from static methods because they apply global state to a class. In object-oriented programming, it’s preferable to store state encapsulated within an object instance. The use of static methods can be an indication of badly constructed code, including code that is difficult to test.
However, static methods are part of the language spec and serve their purpose. They exist for a reason. They exist to be used correctly, with the appropriate care.
When experienced developers first cast sight upon a Laravel Facade, their immediate reaction is often as follows.
Oh no! Static methods are bad. They are hard to test!
In general, this is often true. If the code uses static methods in a poorly conceived way then the code will be difficult to test. However, Laravel has implemented static methods with due care and attention. Let’s delve further into the usage and functionality of the Facade class to further understand why it’s not an immediate risk, and shouldn’t be feared.
If you image a Facade to be the following:
<?php
use DatabaseManager;
class DB
{
public static function table($table)
{
return new DatabaseManager($table);
}
}
Please note that this is not how facades work, I’m just trying to make a point.
Then we consider the usage of the facade in a basic MVC controller, as follows:
<?php
class UsersController
{
public function index()
{
return DB::table('users')->get();
}
}
The code would surely function (if it were real), but we’d be unable to change the database manager. For example, we’d be unable to swap out the database manager for a mock object, that might read data from local files within our tests. This is because the table()
becomes a static factory method, that instantiates a new
database manager for us.
Experienced developers will identify this problem as a case to implement dependency injection. Here’s what that might look like.
<?php
class UsersController
{
private $db;
public function __construct($db)
{
$this->db = $db;
}
public function index()
{
return $this->db->table('users')->get();
}
}
If the database manager is injected into the class through the constructor $db
, and then stored within, and used from a class property, then we can easily pass different database managers into the class, including any mock objects we desire to use when testing.
Note, that you’d normally type-hint an interface to ensure that the database manager contains all the anticipated methods.
In Laravel, we can leverage the automatic dependency resolution nature of the container, to inject our database connection directly. It would look something like this:
<?php
use Illuminate\Database\DatabaseManager;
class UsersController
{
private $db;
public function __construct(DatabaseManager $db)
{
$this->db = $db;
}
public function index()
{
return $this->db->table('users')->get();
}
}
Now, in our tests, we can inject our mock by instantiating the class directly, or we can swap the database connection instance within the Laravel container, and let Laravel do its magic. (Seriously, not magic.)
Clearly, injection through the constructor is much more practical than a static factory method. It’s much more flexible and far better for testing.
However, the ‘Facade’ shown above, was not a facade at all. Let’s take a look at a simplified version of the Laravel Facade base class, which all service facades inherit from.
<?php
abstract class Facade
{
protected static $app;
protected static $resolvedInstance;
protected static function getFacadeAccessor()
{
throw new RuntimeException('Facade does not implement getFacadeAccessor method.');
}
public static function setFacadeApplication($app)
{
static::$app = $app;
}
public static function __callStatic($method, $args)
{
if (!static::$resolvedInstance) {
$key = static::getFacadeAccessor();
static::$resolvedInstance = static::$app->make($key);
}
$instance = static::$resolvedInstance;
return $instance->$method(...$args);
}
}
First of all, the Facade is not an implementation of the ‘Facade pattern’ in truth, it’s more of a proxy. When you call a static method on the facade, it proxies that call to a method of the same name on a service instance held within the framework’s container.
To clarify, both of the following act on the same database connection.
<?php
DB::table();
$db = $app->make('db');
$db->table();
Both call the table()
function on the database instance stored within the Laravel container under the key ‘db’.
Let’s step through our simplified view of the Facade, to see how this works. First, we’ll examine the two class properties.
<?php
protected static $app;
protected static $resolvedInstance;
The first static property contains a reference to the Laravel IoC container. It’s set during the framework bootstrap process using the setFacadeApplication()
method found in the full example above. Since this static property is set on the abstract Facade, it’s also available to all extensions of this abstract.
The next property, $resolvedInstance
, will be set to the service retrieved from the container, the first time the facade is used. This creates a ‘sort of’ singleton pattern. It’s a performance gain, preventing the cost of resolving the service from the container on subsequent method calls on the Facade.
<?php
protected static function getFacadeAccessor()
{
throw new RuntimeException('Facade does not implement getFacadeAccessor method.');
}
Next, we have a protected static method called getFacadeAccessor()
. This method is designed to be overridden when extending the Facade class to return a string, the key which the service represented by the facade is bound within the container. By default, it throws an exception if not implemented. This gives a more informative message to those creating custom facades than if the framework were to instead use an abstract method.
Here’s an example of how the method looks when overridden in the DB
Facade.
<?php
use Illuminate\Support\Facades\Facade;
class DB extends Facade
{
protected static function getFacadeAccessor()
{
return 'db';
}
}
Since it’s a protected method, any calls from within the abstract class will retrieve the value ‘db’. The above sample is all that’s required to create a new facade. A class that extends the Illuminate\Support\Facades\Facade
abstract class, and an overriding getFacadeAccessor()
method returning the string value of the container binding for the service it represents.
To see how this all fits together, let’s take a look at the final method of our simplified abstract facade class. Note that I’ve changed this heavily from the real implementation to increase the clarity of the example. However, for the most part, it functions in a similar way.
<?php
public static function __callStatic($method, $args)
{
if (!static::$resolvedInstance) {
$key = static::getFacadeAccessor();
static::$resolvedInstance = static::$app->make($key);
}
$instance = static::$resolvedInstance;
return $instance->$method(...$args);
}
The __callStatic()
method is a PHP magic method which is executed when a static method is called, that does not exist on the class. Its arguments $method
and $args
will contain the name of the method that was called, and an array of the arguments supplied.
The Laravel Facade intercepts these static method calls to proxy them to the service instance held within the container. First, it must retrieve the service instance from the container (static::$app
) by using the binding retrieved by calling getFacadeAccessor()
. The service is then stored in the resolved property to speed up future calls.
Finally, the originally intended method is called on the service instance, passing the original parameter set. Laravel uses the PHP 5.6 splat (...) operator to pass a sequence of parameters from an array. The result of this method is returned, allowing for a value to be used, or additional methods to be chained.
So you see, each static method call on a Facade is actually passed to a service instance inside the container. This means that we can easily swap the contained instance for a mock, to achieve the same functionality as we saw using dependency injection. This makes Facade’s as easily testable as using dependency injection.
Actually, some would say that Facades can be slightly easier to test, because of some helper methods available on the Facade abstract class. There are several methods for swapping the resolved instance for a Mockery mock object, here’s an example.
<?php
DB::shouldReceive('foo')...
If you’d rather not use mockery, you can swap the stored instance directly with the swap()
method of the Facade. For example:
<?php
DB::swap(new FakeDatabase);
// Call is now made on our 'FakeDatabase' instance.
DB::table();
These methods can be extremely powerful!
I hope you’ve gained an understanding of how the Facade classes function, and why they are not static traps to be feared or avoided. If you’d like to read on, the next section contains an advanced consideration for favoring dependency injection over Facade usage.
Considerations
There is an argument for favoring dependency-injection over Facade usage that will help to explain why the majority of experienced Laravel developers will use constructor-based contract type-hinting to inject their dependencies.
Type-hinting services within the constructor forms it’s own ‘kind of’ contract. If the constructor requires a cache contract implementation, then it must be instantiated with one, and will not function without.
<?php
use Illuminate\Contracts\Cache\Factory as Cache;
class MyController
{
protected $cache;
public function __construct(Cache $cache)
{
$this->cache = $cache;
}
}
If we were to use a facade instead, the class could still be instantiated, and if the service behind the facade was not found in the container, then we’d only find out when we first try to make use of it.
Injection through the constructor also gives additional clarity to the dependencies of the class, that is much easier to observe than scanning the class source for Facade usages.
Finally, dependency injection through the constructor makes it easier to test the class without involving the Laravel framework. We could test the class in isolation, without the use of a container, by instantiating our cache instance ourselves, and passing it as a parameter when instantiating the class. Often, tests work best when they are kept simple and isolated. For this reason, the means of separation from the framework’s container may be useful to you.
If you have any questions about Facades (or anything else for that matter!) then please leave a comment below! I’d be happy to help.
Once again, thanks for reading, and if you enjoyed the article then please share it with your friends!