美文网首页
Laravel框架 之 Facades

Laravel框架 之 Facades

作者: 诺之林 | 来源:发表于2018-04-19 16:14 被阅读13次

    目录

    引入

    基于Laravel框架的开发中 我们经常使用Auth模块的代码如下

    Auth::check();
    

    那么 Laravel框架是如何通过类的静态方法来实现Auth功能的呢?

    答案 就是本文即将要讨论的主题: Facade

    Facade

    首先 Facade作为设计模式的一种 它的作用和优点如下

    外观模式(Facade Pattern) 为子系统中的一组接口提供一个统一的高层接口 使得子系统更容易使用

    这里我们通过Auth的例子来看一下Facade的完整流程

    Auth::check() -> __callStatic(Facade) -> $app[$name]
    
    // 注册IoC容器 $this->app->singleton('auth', function ($app) { return new AuthManager($app); });
    
    // 注册Facades/Auth.php protected static function getFacadeAccessor() { return 'auth'; }
    
    check(AuthManager) -> __call(AuthManager) -> check(SessionGuard) -> check(GuardHelpers)
    

    上述流程的Laravel源码流程具体代码如下

    // config/app.php
    return [
        // alias是Laravel框架的小trick use Auth等同于use Illuminate\Support\Facades\Auth
        'aliases' => [
            'Auth' => Illuminate\Support\Facades\Auth::class,
        ],
    ];
    
    // vendor/laravel/framework/src/Illuminate/Support/Facades/Auth.php
    class Auth extends Facade
    {
        protected static function getFacadeAccessor()
        {
            // 'auth'是IoC容器中的AuthManager单例 详细参考本文 - AuthServiceProvider
            return 'auth';
        }
    }
    
    // vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php
    abstract class Facade
    {
        protected static $app;
    
        public static function setFacadeApplication($app)
        {
            static::$app = $app;
        }
    
        public static function __callStatic($method, $args)
        {
            $instance = static::getFacadeRoot();
    
            // Facade类静态方法实际功能都交由$instance处理
            return $instance->$method(...$args);
        }
    
        public static function getFacadeRoot()
        {
            return static::resolveFacadeInstance(static::getFacadeAccessor());
        }
    
        protected static function resolveFacadeInstance($name)
        {
            // 这里的$name = 'auth' 再配合本文 - AuthServiceProvider 此时得到AuthManager实例
            return static::$app[$name];
        }
    }
    

    RegisterFacades

    Illuminate/Foundation/Http/Kernel.php详细启动流程参考 Laravel框架 之 Session - 启动流程与IoC容器

    // vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php
    class Kernel implements KernelContract
    {
        protected $bootstrappers = [
            \Illuminate\Foundation\Bootstrap\RegisterFacades::class,
            \Illuminate\Foundation\Bootstrap\RegisterProviders::class,
        ];
    
        public function bootstrap()
        {
            if (! $this->app->hasBeenBootstrapped()) {
                $this->app->bootstrapWith($this->bootstrappers());
            }
        }
    }
    
    // vendor/laravel/framework/src/Illuminate/Foundation/Bootstrap/RegisterFacades.php
    class RegisterFacades
    {
        public function bootstrap(Application $app)
        {
            // 启动时给Facade设置$app
            Facade::setFacadeApplication($app);
    
            AliasLoader::getInstance(array_merge(
                $app->make('config')->get('app.aliases', []),
                $app->make(PackageManifest::class)->aliases()
            ))->register();
        }
    }
    
    // vendor/laravel/framework/src/Illuminate/Foundation/AliasLoader.php
    class AliasLoader
    {
        protected static $instance;
    
        private function __construct($aliases)
        {
            $this->aliases = $aliases;
        }
    
        public static function getInstance(array $aliases = [])
        {
            return static::$instance = new static($aliases);
        }
    
        public function register()
        {
            if (! $this->registered) {
                $this->prependToLoaderStack();
    
                $this->registered = true;
            }
        }
    
        protected function prependToLoaderStack()
        {
            spl_autoload_register([$this, 'load'], true, true);
        }
    }
    

    AuthServiceProvider

    // vendor/laravel/framework/src/Illuminate/Auth/AuthServiceProvider.php
    class AuthServiceProvider extends ServiceProvider
    {
        public function register()
        {
            $this->registerAuthenticator();
        }
    
        protected function registerAuthenticator()
        {
            $this->app->singleton('auth', function ($app) {
                return new AuthManager($app);
            });
    
            $this->app->singleton('auth.driver', function ($app) {
                return $app['auth']->guard();
            });
        }
    }
    
    // vendor/laravel/framework/src/Illuminate/Auth/AuthManager.php
    class AuthManager implements FactoryContract
    {
        public function __call($method, $parameters)
        {
            // AuthManager实例实际功能都交由$this->guard()返回的对象处理
            return $this->guard()->{$method}(...$parameters);
        }
    
        public function guard($name = null)
        {
            $name = $name ?: $this->getDefaultDriver();
    
            // 如果没有相应的guard 则通过resolve方法创建
            return $this->guards[$name] ?? $this->guards[$name] = $this->resolve($name);
        }
    
        protected function resolve($name)
        {
            $config = $this->getConfig($name);
    
            if (isset($this->customCreators[$config['driver']])) {
                return $this->callCustomCreator($name, $config);
            }
    
            $driverMethod = 'create'.ucfirst($config['driver']).'Driver';
            // 配置的driver是session 所以实际调用的方法是 
            return $this->{$driverMethod}($name, $config);
        }
    
        public function createSessionDriver($name, $config)
        {
            $provider = $this->createUserProvider($config['provider'] ?? null);
    
            $guard = new SessionGuard($name, $provider, $this->app['session.store']);
    
            return $guard;
        }
    }
    
    // config/auth.php
    return [
        'defaults' => [
            'guard' => 'web',
        ],
    
        'guards' => [
            'web' => [
                'driver' => 'session',
                'provider' => 'users',
            ],
        ],
    
        'providers' => [
            'users' => [
                'driver' => 'eloquent',
                'model' => App\User::class,
            ],
        ],
    ];
    
    // vendor/laravel/framework/src/Illuminate/Auth/SessionGuard.php
    class SessionGuard implements StatefulGuard, SupportsBasicAuth
    {
        use GuardHelpers;
    }
    
    // /Users/kevin/Workspace/laravel-tutorial/session/vendor/laravel/framework/src/Illuminate/Auth/GuardHelpers.php
    trait GuardHelpers
    {
        public function check()
        {
            return ! is_null($this->user());
        }
    }
    

    参考

    相关文章

      网友评论

          本文标题:Laravel框架 之 Facades

          本文链接:https://www.haomeiwen.com/subject/nojwkftx.html