Home  >  Article  >  PHP Framework  >  Why does laravel use facade?

Why does laravel use facade?

WBOY
WBOYOriginal
2022-06-06 16:02:102022browse

In laravel, because the facade can provide a "static" interface for the application's service container, compared to the traditional static method, the "static" interface provided by the facade is equivalent to a static in the underlying class of the service container. Represents that it can provide a more flexible and easier-to-test syntax, so facades are used in laravel.

Why does laravel use facade?

#The operating environment of this article: Windows 10 system, Laravel version 6, Dell G3 computer.

Why laravel uses facade

The facade in Laravel generally follows the basic idea of ​​the facade pattern. The facade in Laravel provides a [static] interface for the application's service container, which is equivalent to a [static representative] in the underlying class of the service container, which can provide more flexible, easy-to-test, and elegant syntax.

For the facade in Laravel, we will often use it, such as caching.

Cache::get('key');

Another example is the database and Redis we often used before.

DB::connection('mysql2')->table('db_test')->get()->toArray();
 
Redis::connection('default')->client()->get('test')

I found that no, the facade is all static methods. But if you click on it, you will find that there is nothing in this facade category!

class Cache extends Facade
{
    protected static function getFacadeAccessor()
    {
        return 'cache';
    }
}

In the Facade class, we don’t need to look at other method functions for now. Just scroll to the bottom and you will find a magic method, __callStatic().

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);
}

__callStatic() means that if the corresponding method is not defined when calling statically, it will enter the __callStatic() method. For example, the Cache::get() method we call is actually currently Neither the Cache facade class nor its parent class Facade defines this method, so it goes directly to __callStatic(). Then, it gets the instance object of our current facade through getFacadeRoot(), and then calls the get() method in the instance object.

Okay, that’s it. In fact, if an interviewer asks you during the interview how to implement the facade mode in Laravel, you can confidently say that the core is the __callStatic() magic method. . So where does this specific instance object come from? Let's continue reading.

Instance Object

Next we look at how to obtain the specific instance object in Facade. Here we have to go back to the service container. But let’s take a look at the entrance first.

In the __callStatic() method, we will see that a static::getFacadeRoot() method is called to obtain the specific instance object.

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

The content of this method is very simple, it just calls the other two methods. Note that getFacadeAccessor() is implemented in each of our facade subclasses. For example, in the example, it is implemented in the Cache class. It just returns an alias for an instance. Remember where this alias was defined? We have seen it in the service container, which is the ones defined in the registerCoreContainerAliases() method in vendor/laravel/framework/src/Illuminate/Foundation/Application.php.

Next, what we mainly look at is the static::resolveFacadeInstance() method. We can tell from the name that it means to solve the facade instance. If this thing does not return an instance object, it really lives up to its name.

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];
    }
}

The first judgment is that if an object is passed in, it will be returned directly. The second judgment is that if there is already one in the current instance array, it will not be created again, which is similar to the effect of flyweight mode. Note, static member array! What does that mean? Static and globally shared, that is to say, after your instance object is created, it can be used elsewhere, in a complete singleton state. The last judgment is that if the app, that is, our service container exists, perform the operation of the service container.

Let’s first take a look at when the app attribute is assigned a value. When talking about service providers, there is a bootstrappers attribute array in the Kernel, which has a RegisterFacades provider. Obviously, it is a service provider used to register the facade. In this service provider, we will see code like this.

public function bootstrap(Application $app)
{
    Facade::clearResolvedInstances();
 
    Facade::setFacadeApplication($app);
 
    AliasLoader::getInstance(array_merge(
        $app->make('config')->get('app.aliases', []),
        $app->make(PackageManifest::class)->aliases()
    ))->register();
}

Among them, Facade::setFacadeApplication() injects the Application object of the service container into the static member variable app of the facade class. Note that it is also static and exists globally.

Then we continue back to the resolveFacadeInstance() method.

protected static function resolveFacadeInstance($name)
{
    // …………
    // …………
    if (static::$app) {
        return static::$resolvedInstance[$name] = static::$app[$name];
    }
}

What's going on here? How can I get an instance object through static::$app[$name]? Don't be excited, don't be anxious, think about how to make an object perform such array operations? We learned it before!

This is the ArrayAccess interface. The several methods it must implement allow the object to be used like an array.

OK, now that we know the principle, let’s see if this is the case and find the parent class of Application vendor/laravel/framework/src/Illuminate/Container/Container.php .

class Container implements ArrayAccess, ContainerContract
{
    // …………
    // …………
    public function offsetGet($key)
    {
        return $this->make($key);
    }
    // …………
    // …………
}

It really looks like Baymax, right? You don’t need me to explain any more, right? The make() method has been explained in the previous service container.

Okay, the rest is up to you. Please find the specific implementation class of Cache based on the alias in the registerCoreContainerAliases() method in vendor/laravel/framework/src/Illuminate/Foundation/Application.php, and then analyze it The implementation of get(), set(), forget() and other methods, and see how they use different cache storage solutions according to our configuration files.

[Related recommendations: laravel video tutorial]

The above is the detailed content of Why does laravel use facade?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn