An elegant design pattern

We often use some classes this way

namespace App\Http\Controllers;

use Illuminate\Support\Facades\Log;

class IndexController extends Controller
{
    public function index()
    {
        Log::info('hahaha~'); }}Copy the code

Register the alias

Start by looking at the part of the corresponding Log class registered in the framework, in the app.php file alias array

 'aliases' => [
        ...
        'Log'=> Illuminate\Support\Facades\Log::class, ... ] .Copy the code

So the actual container is going to parse when you call it

Lluminate, Support, Facades, Log: : class – this class

Let’s look at this class

<? php namespace Illuminate\Support\Facades; class Log extends Facade { protected staticfunction getFacadeAccessor()
    {
        return 'log'; }}Copy the code

Call analysis

The initial method we call is Log::info and we trace it to the parent Facade

Easy to read to simplify some methods

<? php namespace Illuminate\Support\Facades; use Closure; use Mockery; use RuntimeException; use Mockery\MockInterface; abstract class Facade { protected static$app;

    protected static $resolvedInstance; . public staticfunction __callStatic($method.$args)
    {
        $instance = static::getFacadeRoot();

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

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

The call logic here is implemented through the __callStatic magic method

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);
    }
Copy the code

This explains why we can call the corresponding method statically.


To analyze

$instance = static::getFacadeRoot();
Copy the code

It looks like we’re trying to parse out an instance, but the important thing here is

staticThe call will point to the calling class, followed by the inherited class.

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

So here’s the static: : getFacadeAccessor actually point to the Log () class

protected static function getFacadeAccessor()
{
    return 'log';
}
Copy the code

Get an alias from the container

Let’s move on to how to get a date. Okay

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

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

    return static::$resolvedInstance[$name] = static::$app[$name];
}
Copy the code

$app[$name] static::$app[$name

Develop –$appFrom where?

But where is $app assigned if it is an Application object?

Please refer to chapter 4 of Laravel- One Piece series, the handle method of Kernel class parsing.

protected $bootstrappers= [ ... \Illuminate\Foundation\Bootstrap\RegisterFacades::class, ... ] ;Copy the code

Go straight to code

<? php namespace Illuminate\Foundation\Bootstrap; use Illuminate\Foundation\AliasLoader; use Illuminate\Support\Facades\Facade; use Illuminate\Foundation\PackageManifest; use Illuminate\Contracts\Foundation\Application; class RegisterFacades { publicfunction bootstrap(Application $app)
    {
        Facade::clearResolvedInstances();

        Facade::setFacadeApplication($app);

        AliasLoader::getInstance(array_merge(
            $app->make('config')->get('app.aliases', []),
            $app->make(PackageManifest::class)->aliases() ))->register(); }}Copy the code

Delicious ~, the Facade: : setFacadeApplication ($app); Application passed in here.

$app[‘log’] $app[‘log’] $app[‘log’]

Extension – Container binding and parsing!

Chapter 3: Container Class Parsing

The bind() method inside binds the abstraction to the implementation in the container,

This is also container knowledge. The log here is the Application started in advance and helped us to fix ~

Located in __construct() of Application

public function __construct($basePath = null)
{
    ...
    $this->registerBaseServiceProviders(); . }Copy the code
protected function registerBaseServiceProviders() {...$this->register(new LogServiceProvider($this)); . }Copy the code
<? php namespace Illuminate\Log; use Illuminate\Support\ServiceProvider; class LogServiceProvider extends ServiceProvider { publicfunction register()
    {
        $this->app->singleton('log'.function () {
            return new LogManager($this->app); }); }}Copy the code

Return new LogManager($this->app);

finishing

Object in hand, you can arbitrarily call existing methods.

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