目录
引入
基于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());
}
}
网友评论