美文网首页
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