Hello, I’m a Rocket

This is the fourth day of my participation in Gwen Challenge

The introduction

  • Knowledge is your own, don’t be afraid to look at the source code, because it’s easier than you think
  • Today we take you to uncover the mystery of Laravel Facade, from his initiation of registration, to a little bit of parsing loading
  • After learning estimate you will think I Cao so simple, in fact, you want to complex
  • Dynamic facede feels a bit redundant, so write a command to generate a Facade

What is a Facade

Laravel’s Facade is a typical static proxy pattern that lets you statically invoke any method on any object stored in the container

2. Facade startup and registration

The Bootstrap of the Facade is registered in Illuminate Foundation Bootstrap RegisterFacades

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

The default alias configuration is read from the aliases in the APP configuration file. PackageManifest is the automatic package discovery rule added in Laravel 5.5. Here, we temporarily ignore the aliases provided by the PackageManifest package.

public function register()
    {
        if (! $this->registered) {
            $this->prependToLoaderStack();

            $this->registered = true;
        }
    }
    
protected function prependToLoaderStack()
    {
        spl_autoload_register([$this, 'load'], true, true);
    }
Copy the code

All facade autoloads are registered with Illuminate Foundation AliasLoader, and once the PHP-based spl_autoload_register is registered, all subsequent use classes will be autoloaded via the load function. And use the load method first

3. How to define a Facade

You inherit the Illuminate Support Facades Facade class and implement the getFacadeAccessor static method

use Illuminate\Support\Facades\Facade; Class Cache extends Facade {/** * get component registration name ** @return string */ protected static function getFacadeAccessor() {return  'cache'; }}Copy the code

4. How is Facade implemented

When we invoke a facade, we often find that the class has no corresponding method. How does the facade find the implementation class

<?php

use Illuminate\Support\Facades\Config;

class Test
{
    public function index()
    {
        Config::get('app.name');
    }
}


Copy the code

All of the Facades are based on the Illuminate\Support\Facades\Facade class, which defines a __callStatic method so that we can easily use Facades (without having to implement them).

abstract class Facade { public static function getFacadeRoot() { return static::resolveFacadeInstance(static::getFacadeAccessor()); } / / static: : getFacadeAccessor () be subclasses override protected the static function getFacadeAccessor () {throw new RuntimeException (' the 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]; } return static::$resolvedInstance[$name] = static::$app[$name]; 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

Static ::$app[$name] static::$app[$name] The app actually inherits Illuminate Container/ContainerIOC Container and implements PHP’s ArrayAccess. Static ::$app[$name] is the same as app->make($name).

5. Principle of dynamic Facade implementation

Public function load($alias) {Facades\\ if (static::$facadeNamespace && strpos($alias, Static ::$facadeNamespace) === 0) {$this->loadFacade($alias); return true; } if ($this->aliases[$alias]) {return class_alias($this->aliases[$alias], $alias); } } protected function loadFacade($alias) { require $this->ensureFacadeExists($alias); } protected function ensureFacadeExists($alias) { if (file_exists($path = storage_path('framework/cache/facade-'.sha1($alias).'.php'))) { return $path; $this->formatFacadeStub($alias, $path, $this->formatFacadeStub); file_get_contents(__DIR__.'/stubs/facade.stub') )); return $path; }Copy the code

6, the end

With you mutual encouragement, I hope to help youCopy the code