【Laravel—核心源码解析】(三) 核心应用容器类Application

前言

上一章:(二) Composer注册自动加载
本章记录核心应用容器类

正文

入口文件index.php中的

//引入核心应用类, 主要是实现核心类库加载以及Laravel框架中核心的服务容器注册加载等
$app = require_once __DIR__.'/../bootstrap/app.php';
singleton(
    Illuminate\Contracts\Http\Kernel::class,
    App\Http\Kernel::class
);
//注册命令行内核服务
//其它同上
$app->singleton(
    Illuminate\Contracts\Console\Kernel::class,
    App\Console\Kernel::class
);
//注册异常处理服务
//其它同上
$app->singleton(
    Illuminate\Contracts\Debug\ExceptionHandler::class,
    App\Exceptions\Handler::class
);

//返回初始化完成的应用服务容器
return $app;

接下来看看实例应用容器后做了什么

//实例化自动调用进行初始化操作
public function __construct($basePath = null)
{
    if ($basePath) {
        //设置应用路径
        $this->setBasePath($basePath);
    }

    //注册laravel应用程序->到共享实例容器中
    $this->registerBaseBindings();
    //注册基础服务提供者(事件,路由,日志)
    $this->registerBaseServiceProviders();
    //注册核心类别名到容器中,内部根据配置的服务数组进行遍历绑定别名
    $this->registerCoreContainerAliases();
}
setBasePath:
public function setBasePath($basePath)
{
    //设置基础路径
    $this->basePath = rtrim($basePath, '\/');

    //该方法主要是根据上面的设置的basePath来设置各个应用目录的路径,
    //并绑定至服务容器中,还未找到绑定后具体是在哪里使用的,后续有发现会再做更新
    $this->bindPathsInContainer();

    return $this;
}
registerBaseBindings:
/**
  * 在容器中注册一个共享的现有实例
  * Register the basic bindings into the container.
  *
  * @return void
 */
protected function registerBaseBindings()
{
    //设置单例
    static::setInstance($this);

    //将当前类实例绑定到成员变量instances中,标示为app
    $this->instance('app', $this);
    //将当前类实例绑定到成员变量instances中,标示为Container::class
    $this->instance(Container::class, $this);
    //以单例的形式,绑定Mix类到成员变量bindings中,标示为Mix::class
    //只传入第一个参数标示未传入具体实现时,会先根据传入的标示来获取具体
    //的实现,再将其进行保存
    $this->singleton(Mix::class);

    //将PackageManifest类实例绑定到成员变量instances中,标示为PackageManifest::class
    //这里不属于主要流程不必深究,感兴趣可以自行搜索Laravel包自动发现
    $this->instance(PackageManifest::class, new PackageManifest(
        //第一个参数Filesystem类主要提供一些操作在后续PackageManifest中会使用到
        //后两个参数就是将基础路径和packages.php的路径配置进去,

        //composer安装的所有扩展包的composer.json文件内容以及完整的映射
        //都会保存在vendor/composer/installed.json中,Laravel通过解析该
        //文件进行服务自动发现
        new Filesystem, $this->basePath(), $this->getCachedPackagesPath()
    ));
}
registerBaseServiceProviders:
protected function registerBaseServiceProviders()
{
    //服务提供者:服务容器只是将具体的服务进行注册收纳及解析使
    //用,通常一些不集中的服务都是通过在框架各个位置进行注册,
    //而服务提供者则是将与自身相关或依赖的服务进行集合来注册,
    //类似路由,Redis之类的服务都会创建与之相关的路由服务提供
    //者,Redis服务提供者,再具体的提供者类内部进行集合注册,
    //好处就是相关的服务可以用放在一起进行集中管理
    //注册事件的服务提供者
    $this->register(new EventServiceProvider($this));
    //注册路由的服务提供者
    $this->register(new LogServiceProvider($this));
    //注册日志的服务提供者
    $this->register(new RoutingServiceProvider($this));
}
registerBaseServiceProviders->register:
//注册服务提供者
public function register($provider, $force = false)
{
    //判断是否已经注册过,注册过则直接返回之前注册的实例
    //这里就不贴getProvider具体的代码了简述一下
    //通过register注册的实例会保存在成员变量serviceProviders中
    //用array_filter方法遍历成员变量serviceProviders,进行instanceof
    //将符合的结果筛选出来,通过array_values获取值并返回
    if (($registered = $this->getProvider($provider)) && ! $force) {
         return $registered;
    }
    //如果是字符串,就解析出对应的实例,其实就是通过类名进行new的操作
    if (is_string($provider)) {
        $provider = $this->resolveProvider($provider);
    }
     //服务提供者会继承Illuminate\Support\ServiceProvider抽象类,继承的类都会实现
    //抽象类中定义的register方法,服务提供者通常都会在register方法中将服务对应或者
    //需要使用的类绑定到服务容器中去方便后续使用
    $provider->register();
    //判断传入的实例中是否有bindings成员变量,有就遍历对其配置的类进行绑定
    if (property_exists($provider, 'bindings')) {
        foreach ($provider->bindings as $key => $value) {
            $this->bind($key, $value);
        }
    }
    //判断传入的实例中是否有bindings成员变量,有就遍历对其配置的类以单例的形式进行绑定
    if (property_exists($provider, 'singletons')) {
        foreach ($provider->singletons as $key => $value) {
            $this->singleton($key, $value);
        }
    }

    //将注册完的服务提供者存入成员变量serviceProviders中
    //将注册完的服务提供者的类名存入成员变量loadedProviders中
    $this->markAsRegistered($provider);

    //TODO 1
    if ($this->isBooted()) {
        //执行服务提供者内部的boot函数
        $this->bootProvider($provider);
    }

    return $provider;
}
registerCoreContainerAliases
//注册核心类别名到容器中,内部根据配置的服务数组进行遍历绑定别名
//只贴了小部分代码
public function registerCoreContainerAliases()
{
    foreach ([
        'app'                  => [self::class, \Illuminate\Contracts\Container\Container::class, \Illuminate\Contracts\Foundation\Application::class, \Psr\Container\ContainerInterface::class],
        'auth'                 => [\Illuminate\Auth\AuthManager::class, \Illuminate\Contracts\Auth\Factory::class],
        'auth.driver'          => [\Illuminate\Contracts\Auth\Guard::class]
    ] as $key => $aliases) {
        foreach ($aliases as $alias) {
            //遍历出来的子项进行别名注册
            //方法内部判断两个参数不能相等后将别名对应关系存入成员变量aliases和abstractAliases中
            $this->alias($key, $alias);
        }
    }
}

END

你可能感兴趣的:(【Laravel—核心源码解析】(三) 核心应用容器类Application)