Posts | About

How Laravel Facades Work Under The Hood

July 21, 2020 by Areg Sarkissian

Laravel Facade classes

The Laravel Facade classes are static wrappers around the framework service class instances resolved out of the Laravel container.

Framework service classes are the classes that provide core framework features such as routing and caching. Facade classes give us a convenient way to access methods of these service classes using static class method semantics.

Even though the method calls on the Facade classes appear to be static methods, they are actually dynamic methods that resolve, from the container, an instance of a service class that actually implements the method. Then the method is called on the resolved instance of the service class.

How facade service class resolution works

Every facade class must implement the getFacadeAccessor method. This method will return a key string that will be used to resolve, from the container, the service class instance associated with the facade.

This key string can be the fully namespace qualified name of service class that we want to resolve from the container, can be the fully namespace qualified name of the contract interface that the service class implements or can be an alias string, for the service class, called Service Container Binding key.

The important thing to note is that in order for the service to be able to be resolved, the framework must have registered the service that needs to be resolved using the key string that we return from the facade getFacadeAccessor method.

The list of fully namespace qualified class name and alias key mappings for Laravel Facade classes can be found in the Laravel Facades documentation at https://laravel.com/docs/7.x/facades#facade-class-reference

As an example I am showing below the App and Auth facade class mappings from the documentation:

Facade class Service Container Binding
App Illuminate\Foundation\Application app
Auth Illuminate\Auth\AuthManager auth

Looking at the the App facade we can see that it resolves an instance of Illuminate\Foundation\Application service class. There is also a Service Container Binding alias called app registered with the container for that service class.

So if we look at the source code of the App facade class we can see that its getFacadeAccessor method returns the string app which will be used to resolve the Illuminate\Foundation\Application service class out of the container.

The Request facade

As an example of how facades work under the hood, lets look at the Illuminate\Support\Facades\Request facade class shown below:

namespace Illuminate\Support\Facades;

 /**
 * @method static void flush()
 * @see \Illuminate\Http\Request
 */
class Request extends Facade
{
    /**
     * Get the registered name of the component.
     *
     * @return string
     */
    protected static function getFacadeAccessor()
    {
        return 'request';
    }
}

The comments at the top of the every facade class implemented by the framework will have a list of methods that you can call on that facade class. These are listed using the @method attribute. The comments also list the service class that will be resolved that those methods are defined in. This is listed using the @see attribute.

I am showing only one of the @method comments of the Illuminate\Support\Facades\Request facade which shows that static void flush() method is one of the methods that we can call on the Request facade. Also the @see attribute shows that the Request facade resolves the Illuminate\Http\Request service class that is the class that defines the actual static void flush() method that will be called when we call Request::flush().

As you can see The Request facade only contains the required implementation of getFacadeAccessor.

Now Let’s see what happens when the Illuminate\Support\Facades\Request::flush() method is called on the Request facade.

Since there is no implementation for that method and it is a static method call, the static __callStatic method of the base Illuminate\Support\Facades\Facade class will be called. This is where all the magic of the facade class happens and will be covered it the next section.

The Facade base class

The base Illuminate\Support\Facades\Facade class that the Illuminate\Support\Facades\Request facade extends is where the service class associated with the facade is resolved and then its method invoked.

A partial implementation of the class is shown below:

namespace Illuminate\Support\Facades;

use Closure;
use Mockery;
use Mockery\MockInterface;
use RuntimeException;

abstract class Facade
{
    protected static $app;

    protected static $resolvedInstance;

    public static function __callStatic($method, $args)
    {
        $instance = static::getFacadeRoot();

        if (! $instance) {
            throw new RuntimeException('A facade root has not been set.');
        }

        return $instance->$method(...$args);
    }

    public static function getFacadeRoot()
    {
        return static::resolveFacadeInstance(static::getFacadeAccessor());
    }


    protected static function getFacadeAccessor()
    {
        throw new RuntimeException('Facade does not implement getFacadeAccessor method.');
    }

    protected static function resolveFacadeInstance($name)
    {
        if (is_object($name)) {
            return $name;
        }

        if (isset(static::$resolvedInstance[$name])) {
            return static::$resolvedInstance[$name];
        }

        if (static::$app) {
            return static::$resolvedInstance[$name] = static::$app[$name];
        }
    }

    public static function setFacadeApplication($app)
    {
        static::$app = $app;
    }
}

As I detailed in the previous section the __callStatic method is called when we call the Request::flush() method. When this method is called the action method name flush is passed to it as the first parameter. If the flush method had parameters, then those parameters would have been passed as the second parameter of the __callStatic method. But in this case the second parameter will be null or empty.

The __callStatic method first calls the static::getFacadeRoot() method of the base facade class to resolve the instance of the actual Illuminate\Http\Request service class that implements the flush method.

Once the Illuminate\Http\Request instance is returned, the __callStatic method calls the flush method on that instance by calling $instance->$method(...$args) which uses the method parameter $method to call the flush method.

How getFacadeRoot resolves the service class

As we saw in the previous section, when the __callStatic method calls the static::getFacadeRoot() of the base Illuminate\Support\Facades\Facade class, the Illuminate\Http\Request service class is resolved. The way that happens is described below:

The static::getFacadeRoot() method of the base Facade class calls the static::resolveFacadeInstance method of the base Facade class passing to the method the result of the call to the static::getFacadeAccessor method.

In other words static::getFacadeRoot() first calls static::getFacadeAccessor, then calls static::resolveFacadeInstance passing to it the resulting string returned by the static::getFacadeAccessor call.

The base Illuminate\Support\Facades\Facade class has a default implementation of protected static function getFacadeAccessor() method that is overridden by every facade class that extends it.

The Illuminate\Support\Facades\Request facade, that extends the base Facade class, overrides this method. The overridden implementation simply returns the string 'request'.

So when the base Facade class static::getFacadeRoot() method calls static::getFacadeAccessor, it is actually calling the Illuminate\Support\Facades\Request facade’s overridden implementation of static::getFacadeAccessor which returns the string 'request'.

This 'request' string is the same string as the string used to register an alias for the Illuminate\Http\Request service class with the application container.

You can see this string listed in the Facade list mappings for the Request facade in the Laravel Facade documentation https://laravel.com/docs/7.x/facades#facade-class-reference that I previously mentioned.

So to reiterate, the static::getFacadeRoot() of the base Facade class calls the overridden static::getFacadeAccessor method of the Illuminate\Support\Facades\Request class that returns the string 'request' that the static::getFacadeRoot() method then passes to the static::resolveFacadeInstance method of the base Facade class.

Inside the method, the return static::$resolvedInstance[$name] = static::$app[$name]; line is executed. This line resolves the Illuminate\Http\Request service class from the static::$app container using the 'request' string passed in as the $name parameter. It sets the resolved instance into the static::$resolvedInstance array using the same $name parameter then returns the resolved instance.

Note: sometimes we already have access to a resolved instance of the service class. This instance is passed as the $name parameter to resolveFacadeInstance so it is simply returned via the line return $name; at the top of the resolveFacadeInstance method

As stated in the previous section, once the instance is returned, the flush method called on the facade is called on the instance.

A note on the alias string returned by getFacadeAccessor. This is the string used to bind an alias for the Illuminate\Http\Request service class in the Laravel container. So that it can be resolved out of the container using that alias string. That is not to be confused with Facade alias strings that are short strings mapped to Facade classes so that a Facade class can be referenced using its alias string instead of requiring the fully namespace qualified Facade class name.