2.2 - Laravel - 5.6 - Facade - 关于 facade 加载

larave在启动的时候会预先加载facade 已经配置好的映射。以便在后面facade调用的时候使用。

启动流程是这样的

1.起始页面 index.php 加载了
$app = require_once __DIR__.'/../bootstrap/app.php';

2.在bootstrap/app.php中加载

$app->singleton(
    Illuminate\Contracts\Http\Kernel::class,
    App\Http\Kernel::class
);

3.然后在 App\Http\Kernel::class父类中加载了

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

4.这个RegisterFacades::class 就是facade预加载的核心类,只有一个bootstrap方法:

public function bootstrap(Application $app)
    {
        //1 第一步
        Facade::clearResolvedInstances();
        //2 第二步
        Facade::setFacadeApplication($app);
        //3 第三步
        AliasLoader::getInstance(array_merge(
            $app->make('config')->get('app.aliases', []),
            $app->make(PackageManifest::class)->aliases()
        ))->register();
    }

bootstrap方法做了如下的事情:
1.清空对象类数组实例
1.1 清空处理就是置空。

public static function clearResolvedInstances()
    {
        static::$resolvedInstance = [];
    }

2.把容器放入facade对象,就是facade中的set方法
在2.1 上一章的abstract class Facade中,我们使用setFacadeApplication方法来注入容器对象(app)给facade类。

public static function setFacadeApplication($app)
{
    static::$app = $app;
}

3.把facade对象从config中读取后注册(这个注册就是建立关系)
3.1 获取所有配置的facade对应关系

$app->make('config')->get('app.aliases', []),
            $app->make(PackageManifest::class)->aliases()

默认的别名配置是从 app 配置文件下的 aliases数组 读取的,PackageManifest 是 laravel 5.5 新增的 包自动发现规则,这里我们暂时不考虑,还没研究。

3.2 使用AliasLoader的getInstance方法注册这些对应关系。

public static function getInstance(array $aliases = [])
    {
        if (is_null(static::$instance)) {
            return static::$instance = new static($aliases);
        }

        $aliases = array_merge(static::$instance->getAliases(), $aliases);

        static::$instance->setAliases($aliases);

        return static::$instance;
    }

3.2.1 第一步 如果当前这个实例为空,重新生成一个
3.2.2 把当前已经有的alias(别名)和传入的alias合并
3.2.3 返回当前这个AliasLoader实例,包含了所有该有的别名映射。

3.3 使用 register()方法注册

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

            $this->registered = true;
        }
    }

3.3.1 prependToLoaderStack函数通过使用php自动加载方法spl_autoload_register 把当前对象(当前AliasLoader类中有个load方法)的load方法 放到SPL __autoload函数队列的头部。如果php运行中触发了没有声明的类,会自动运行load这个函数。load函数通常都要引入(require 或者include)需要的类,如果没有,就会在队列中继续寻找需要的类。(详细部分放在下一章 2.3)

protected function prependToLoaderStack()
{
    spl_autoload_register([$this, 'load'], true, true);
}

3.3.1.1 然后看下这个load函数,主要存在两种情况。

public function load($alias)
    {
        if (static::$facadeNamespace && strpos($alias, static::$facadeNamespace) === 0) {
            $this->loadFacade($alias);
            return true;
        }
        if (isset($this->aliases[$alias])) {
            return class_alias($this->aliases[$alias], $alias);
        }
    }

a.判断facade的别名中是否存在启始位置为Facades\\ 的字段, 如果有就要调用loadFacade()去加载。
b.如果没有,这里是核心方法,使用了php的class_alias方法把别名和真实的类建立关系

比如我们直接使用 Route 时, 我们其实是调用的Illuminate\Support\Facades\Route类。

说到底,这个整个第三步其实就是使用了class_alias给配置项产生一个别名。然后存起来

本作品采用《CC 协议》,转载必须注明作者和本文链接
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!