Laravel 之道第四章:步调 Laravel 容器 Application 的初始化

栏目: PHP · 发布时间: 8年前

内容简介:Laravel 之道第四章:步调 Laravel 容器 Application 的初始化

Step.019--项目根目录/public/index.php #41

$app = require_once __DIR__.'/../bootstrap/app.php';

执行 项目根目录/bootstrap/app.php 文件,取得返回值,赋值给 $app。

下一步,进入 项目根目录/bootstrap/app.php 文件

Step.020--项目根目录/bootstrap/app.php #14

$app = new Illuminate\Foundation\Application(
    realpath(__DIR__.'/../')
);

承接上一步,开始 $app 容器的初始化工作

new 一个 Laravel 容器对象,注意这个类还没有在内存中。需要调用上一章注册号的自动加载函数,将类包含到内存中,然后才能 new

realpath 返回一个完整、规范化、去掉 ../ 的绝对路径。 realpath 官方文档

下一步,进入 项目根目录/vendor/composer/ClassLoader.php 文件中,执行之前注册好的自动加载方法,并携带 "Illuminate\Foundation\Application"参数

Step.021--项目根目录/vendor/composer/ClassLoader.php #321

public function loadClass($class)
{  // $class: "Illuminate\Foundation\Application"
    if ($file = $this->findFile($class)) {
        includeFile($file);

        return true;
    }
}

承接上一步,开始加载 "Illuminate\Foundation\Application" 类进入内存中,以供 new 使用

如果 $this->findFile($class) 返回非空字符串,则执行 if 代码块,调用 includFile 方法,将对应的类文件包含执行。

下一步,进入 $this->findFile($class) 方法中,并携带 "Illuminate\Foundation\Application" 参数

Step.022--项目根目录/vendor/composer/ClassLoader.php #338

public function findFile($class)
{
    // class map lookup
    if (isset($this->classMap[$class])) {
        return $this->classMap[$class];  // $class: "Illuminate\Foundation\Application"
    }
    // 由于上面条件满足,下面不执行,暂时先不管

}

承接上一步,开始寻找 "Illuminate\Foundation\Application" 是否在当前对象的 classMap 属性中(此属性为数组),即 $this->classMap[$class] 如果有设置,则返回它。到上一步的 $file 变量

下一步,因为在属性 "classMap" 找到了键为 "Illuminate\Foundation\Application" 的键值对,故返回其值至上一步的 "$file" 变量

Step.023--项目根目录/vendor/composer/ClassLoader.php #322

includeFile($file);  // $file: "D:\www\learn\vendor\composer/../laravel/framework/src/Illuminate/Foundation/Application.php"

承接上一步,"$file" 为真,执行此语句,调用 includeFile 方法,以 "$file" 为参数

下一步,进入 includFile 函数

Step.024--项目根目录/vendor/composer/ClassLoader.php #422

function includeFile($file)  
{
    include $file;  // $file: "D:\www\learn\vendor\composer/../laravel/framework/src/Illuminate/Foundation/Application.php"
}

承接上一步,开始加载 $file 文件到内存中

所包含执行的类文件,如果其类继承的父类和实现的接口类,同样需要自动加载。则重复 loadClass 方法。如果父类又继承了父类和实现接口类,也是需要加载,则同样需要重复 loadClass 方法,直到所有需要的类全部加载到内存。才开始真正实例化,并调用构造函数

下一步,具体加载流程如上所述,此处不细看,直接进入 "Illuminate\Foundation\Application" 类中的构造方法中

Step.025--项目根目录/vendor/laravel/framework/src/Illuminate/Foundation/Application.php #140

public function __construct($basePath = null)
{
    if ($basePath) {  // $basePath: "D:\www\learn"
        $this->setBasePath($basePath);
    }

    $this->registerBaseBindings();

    $this->registerBaseServiceProviders();

    $this->registerCoreContainerAliases();
}

承接上一步,从第 20 步中拿到项目根目录的绝对路径参数作为 $basePath 变量的值,开始容器类的构造方法

上面第一行的意思是如果 $basePath 不为空,则设置项目 PATH 基本环境变量。

接下来的三个方法调用分别是

$this->registerBaseBindings(): 注册应用基本绑定,如 app 指向容器对象

$this->registerBaseServiceProviders(): 注册基本服务提供者

$this->registerCoreContainerAliases(): 注册核心容器别名

下一步,进入 $this->setBasePath($basePath) 看看此方法的执行流程

Step.026--项目根目录/vendor/laravel/framework/src/Illuminate/Foundation/Application.php #267

public function setBasePath($basePath)
{
    $this->basePath = rtrim($basePath, '\/');  // $basePath: "D:\www\learn"

    $this->bindPathsInContainer();

    return $this;
}

承接上一步,开始设置 Laravel 运行的基本路径环境变量

代码中,第一行调用 PHP 的 rtrim 函数,修剪项目根目录路径字符串,去掉尾部的 '/',并赋值给当前对象的 basePath 属性

下一步,进入 $this->bindPathsInContainer() 看一下执行流程

Step.027--项目根目录/vendor/laravel/framework/src/Illuminate/Foundation/Application.php #281

protected function bindPathsInContainer()
{
    $this->instance('path', $this->path());
    $this->instance('path.base', $this->basePath());
    $this->instance('path.lang', $this->langPath());
    $this->instance('path.config', $this->configPath());
    $this->instance('path.public', $this->publicPath());
    $this->instance('path.storage', $this->storagePath());
    $this->instance('path.database', $this->databasePath());
    $this->instance('path.resources', $this->resourcePath());
    $this->instance('path.bootstrap', $this->bootstrapPath());
}

承接上一步,开始调用父类的 instance 方法,注册基本路径环境变量

$this->path() 返回就是 '项目根目录/app' ,即 app 目录路径。同理:

$this->basePath():项目根目录路径

$this->langPath():项目语言包路径,即 '项目根目录/resources/lang'

$this->configPath():项目配置文件路径,即 '项目根目录/config'

$this->publicPath():项目 public 文件夹路径

$this->storagePath():项目 storage 文件夹路径

$this->databasePath():项目 database 文件夹路径

$this->bootstrapPath():项目 bootstrap 文件路径

以上所述路径,皆为绝对路径

下一步,让我们看看 $this->path() 如何执行的

Step.028--项目根目录/vendor/laravel/framework/src/Illuminate/Foundation/Application.php #300

public function path($path = '')
{
    return $this->basePath.DIRECTORY_SEPARATOR.'app'.($path ? DIRECTORY_SEPARATOR.$path : $path);  // $path: ''
}

承接上一步,获取 app 文件夹绝对路径,并返回

DIRECTORY_SEPARATOR:PHP 常量,代表目录分隔符

($path ? DIRECTORY_SEPARATOR.$path : $path):代表三元运算符,因为 $path 参数并未从上一步传入进来,故为空,则 $path 为假,取 $path 与前面的字符串拼接

下一步,将获取的 app 文件夹绝对路径返回到上一步,并执行父类的 instance 方法,下面我们看一下这个 instance 方法

Step.029--项目根目录/vendor/laravel/framework/src/Illuminate/Container/Container.php #385

public function instance($abstract, $instance)
{  // $abstract: "path"; $instance: "D:\www\learn\app"
    $this->removeAbstractAlias($abstract);

    $isBound = $this->bound($abstract);

    unset($this->aliases[$abstract]);

    // We'll check to determine if this type has been bound before, and if it has
    // we will fire the rebound callbacks registered with the container and it
    // can be updated with consuming classes that have gotten resolved here.
    $this->instances[$abstract] = $instance;

    if ($isBound) {
        $this->rebound($abstract);
    }

    return $instance;
}

承接上一步,此方法的作用就是将 $abstract (摘要,或者称标识,只能是字符串类型)作为键,$instance (实例,可以是对象类型),作为值。叠加给当前对象的 instances 属性(此属性的值是数组类型)

下一步,$this->removeAbstractAlias($abstract) 从字面上看,指移除摘要的别名,我们看看具体执行

Step.030--项目根目录/vendor/laravel/framework/src/Illuminate/Container/Container.php #409

protected function removeAbstractAlias($searched)
{  // $searched: "path"
    if (! isset($this->aliases[$searched])) {
        return;
    }

    foreach ($this->abstractAliases as $abstract => $aliases) {
        foreach ($aliases as $index => $alias) {
            if ($alias == $searched) {
                unset($this->abstractAliases[$abstract][$index]);
            }
        }
    }
}

承接上一步,此方法 if 执行段判断有没有摘要的别名,有则执行 foreach 段去移除别名,没有则返回

由于第一次执行,所以 $this->aliases[$searched] 并没有设置,故返回

下一步,继续 instance 方法,看一下 $isBound = $this->bound($abstract) 中 bound 方法返回何值

Step.031--项目根目录/vendor/laravel/framework/src/Illuminate/Foundation/Application.php #745

public function bound($abstract)
{  // $abstract: "path"
    return isset($this->deferredServices[$abstract]) || parent::bound($abstract);
}

承接上一步,此方法意思是,查看 $abstract 这个摘要有没有绑定过。

由于第一次执行故 isset($this->deferredServices[$abstract]) 返回 false,|| 未发生短路,执行 parent::bound($abstract)

下一步,看一下 parent::bound($abstract) 的执行流程

Step.032--项目根目录/vendor/laravel/framework/src/Illuminate/Container/Container.php #151

public function bound($abstract)
{  // $abstract: "path"
    return isset($this->bindings[$abstract]) ||
           isset($this->instances[$abstract]) ||
           $this->isAlias($abstract);
}

承接上一步,由于 $this->bindings[$abstract] 和 $this->instances[$abstract] 均未设置,故未短路,执行 $this->isAlias($abstract)

下一步,看一下 $this->isAlias($abstract)

Step.033--项目根目录/vendor/laravel/framework/src/Illuminate/Container/Container.php #201

public function isAlias($name)
{  // $name: "path"
    return isset($this->aliases[$name]);
}

承接上一步,由于 $this->aliases[$name] 未设置,故返回 false。

从这一步开始返回,一直返回到 instance 方法的 $isBound = $this->bound($abstract) 一行,皆为 false。 故 $isBound 值为 false

下一步,执行 instance 方法的 unset($this->aliases[$abstract]),由于未设置 $this->aliases[$abstract],在这段流程中,没有意义。我们看下一行 $this->instances[$abstract] = $instance;

Step.034--项目根目录/vendor/laravel/framework/src/Illuminate/Container/Container.php #394

$this->instances[$abstract] = $instance// $abstract: "path"; $instance: "D:\www\learn\app"

承接上一步,以 $abstract 为键,$instance 为值,叠加给 instances 属性

此行就是 instance 方法核心了

下一步,根据 $isBound 的值判断,是否调用重绑定方法

Step.035--项目根目录/vendor/laravel/framework/src/Illuminate/Container/Container.php #396

if ($isBound) {  // $isBound: false
    $this->rebound($abstract);
}

return $instance;

承接上一步,从此处开始,一直返回到 instance 方法调用行

由于,$isBound 为 false,不执行 if 里的代码,直接返回 $instance。由第 27 步看并没有变量接受返回值,故此行返回在这没有意义

由于第 27 步都是调用 instance 方法,注册 instances 属性键值对,故直接执行到方法尾部。让我们看看最后执行的结果,上图

Laravel 之道第四章:步调 Laravel 容器 Application 的初始化

下一步,重新回到 Application 的构造方法中,看一下 $this->registerBaseBindings()

Step.036--项目根目录/vendor/laravel/framework/src/Illuminate/Foundation/Application.php #166

protected function registerBaseBindings()
{
    static::setInstance($this);

    $this->instance('app', $this);

    $this->instance(Container::class, $this);

    $this->instance(PackageManifest::class, new PackageManifest(
        new Filesystem, $this->basePath(), $this->getCachedPackagesPath()
    ));
}

承接上一步,开始注册基本绑定

设置容器静态属性 $instance,其值为当前对象本身。分别以 "app" 和 "Illuminate\Container\Container" 为键,当前对象本身为值,叠加到 instances 属性中,再以 "Illuminate\Foundation\PackageManifest" 为键,PackageManifest 类对象为值,叠加到 instances 属性中

Container::class: 此句返回的是类的标准全类名(包含完整的命名空间),是字符串类型

下一步,我们看一下 static::setInstance($this)

Step.037--项目根目录/vendor/laravel/framework/src/Illuminate/Container/Container.php #1186

public static function setInstance(ContainerContract $container = null)
{  // $container: 当前对象本身
    return static::$instance = $container;
}

承接上一步,设置 $instance 静态属性为当前对象本身

由于PackageManifest 类实例化所需的参数 Filesystem 类的对象无构造函数,先不用看 Filesystem 类的实例化,注意先自动加载 PackageManifest 类,然后自动加载 Filesystem 类

$this->basePath() 返回项目根目录的绝对路径,不用看,很简单

$this->getCachedPackagesPath() 返回 Packages 包缓存文件路径,不用看,很简单

下一步,看一下 PackageManifest 类实例化执行的构造函数

Step.038--项目根目录/vendor/laravel/framework/src/Illuminate/Foundation/PackageManifest.php #53

public function __construct(Filesystem $files, $basePath, $manifestPath)
{  // $files: Filesystem 类的实例; $basePath: "D:\www\learn"; $manifestPath: "D:\www\learn\bootstrap/cache/packages.php"
    $this->files = $files;
    $this->basePath = $basePath;
    $this->manifestPath = $manifestPath;
    $this->vendorPath = $basePath.'/vendor';
}

承接上一步,执行 PackageManifest 类的构造函数

可以看出,构造函数,仅做了属性赋值运算,未调用其它方法

是到 registerBaseBindings 方法完成的时候了,来,上图看执行结果

Laravel 之道第四章:步调 Laravel 容器 Application 的初始化

下一步,查看 $this->registerBaseServiceProviders() 执行流程

Step.039--项目根目录/vendor/laravel/framework/src/Illuminate/Foundation/Application.php #184

protected function registerBaseServiceProviders()
{
    $this->register(new EventServiceProvider($this));

    $this->register(new LogServiceProvider($this));

    $this->register(new RoutingServiceProvider($this));
}

承接上一步,开始注册事件服务、日志服务和路由服务

注册方式,采用的是 IoC/DI,即控制反转与依赖注入。具体如何实现的我们详细看代码

实例化 EventServiceProvider 类之前,需调用之前注册好的自动加载方法,从 classMap 属性中获取 EventServiceProvider 类所在绝对路径,然后加载到内存,最后实例化调用构造函数

下一步,看一下 EventServiceProvider 的类构造函数(注:其构造函数是父类的构造函数)

Step.040--项目根目录/vendor/laravel/framework/src/Illuminate/Support/ServiceProvider.php #43

public function __construct($app)
{
    $this->app = $app;
}

承接上一步,把容器对象赋值到当前服务提供者对象中的 app 属性上。

这就叫依赖注入:事件服务应用依赖 Laravel 容器

下一步,看一下第 39 步的 register 方法是执行的

Step.041--项目根目录/vendor/laravel/framework/src/Illuminate/Foundation/Application.php #559

public function register($provider, $options = [], $force = false)
{
    // 这段意思是,查看事件服务对象之前有没有注册过, 有则返回注册过的事件服务对象
    if (($registered = $this->getProvider($provider)) && ! $force) {  // $provider: 事件服务对象; $options: []; $force: false
        return $registered;
    }

    // 这段意思是,如果 $provider 是字符串(但必须是全类名),则根据其解析出对象
    if (is_string($provider)) {  // false 不执行里面的代码
        $provider = $this->resolveProvider($provider);
    }

    // 这段意思是,事件服务对象有没有 register 方法,有则调用
    if (method_exists($provider, 'register')) {
        $provider->register();
    }

    // 这段意思是,事件服务对象有没有 bindings 属性,把属性内的键值对绑定到容器里面
    if (property_exists($provider, 'bindings')) {
        foreach ($provider->bindings as $key => $value) {
            $this->bind($key, $value);
        }
    }

    // 这段意思是,事件服务对象有没有 singletons 属性,把属性内的键值对绑定到容器里面
    if (property_exists($provider, 'singletons')) {
        foreach ($provider->singletons as $key => $value) {
            $this->singleton($key, $value);
        }
    }

    // 记录注册的服务对象,防止重复注册,提高效率
    $this->markAsRegistered($provider);

    // 我这段基本没怎么运行到,具体作用不是很清楚
    if ($this->booted) {
        $this->bootProvider($provider);
    }

    return $provider;
}

承接上一步,开始注册事件服务对象, register 方法具体流程解释看代码中注释

下一步,看一下 $this->getProvider($provider) 如何取得缓存好的对象

Step.042--项目根目录/vendor/laravel/framework/src/Illuminate/Foundation/Application.php #609

public function getProvider($provider)
{  // $provider: 事件服务对象
    return array_values($this->getProviders($provider))[0] ?? null;
}

承接上一步,通过 null 合并运算,如果 ?? 前的值不为null,则返回?? 前的值,否则返回 null

array_values:作用是返回含所有值的索引数组;上面的 [0] 指取数组的第一个值

下一步,看一下 $this->getProviders($provider)

Step.043--项目根目录/vendor/laravel/framework/src/Illuminate/Foundation/Application.php #620

public function getProviders($provider)
{   // $provider: 事件服务对象
    $name = is_string($provider) ? $provider : get_class($provider);  // $name: "Illuminate\Events\EventServiceProvider"

    return Arr::where($this->serviceProviders, function ($value) use ($name) {
        return $value instanceof $name;
    });
}

承接上一步,通过容器中的 serviceProviders 属性来获取相应服务提供对象

$name 赋值哪一行:指如果 $provider 是字符串,则返回其本身,如果不是字符串(一定是对象),则返回对象所属类的全名

下一步, Arr::where() 方法,如果遍历 serviceProviders 属性,找到属于 $name 的对象

Step.044--项目根目录/vendor/laravel/framework/src/Illuminate/Support/Arr.php #604

public static function where($array, callable $callback)
{
    return array_filter($array, $callback, ARRAY_FILTER_USE_BOTH);
}

承接上一步,利用 php 中的 array_filter 数组元素过滤方法,来取得需要的值

合并两步,等同于下列代码

public function getProviders($provider)
{   // $provider: 事件服务对象
    $name = is_string($provider) ? $provider : get_class($provider);  // $name: "Illuminate\Events\EventServiceProvider"

    return array_filter($this->serviceProviders, function ($value) use ($name) {
        return $value instanceof $name;
    }, ARRAY_FILTER_USE_BOTH);
}

array_filter 函数详解

由于第一次运行,serviceProviders 属性是空数组,故第 41 步中的 $registered 为 null,if 里面的代码不执行

下一步,重点 $provider->register() 即 事件服务对象中的 register 方法

Step.045--项目根目录/vendor/laravel/framework/src/Illuminate/Events/EventServiceProvider.php #15

public function register()
{
    $this->app->singleton('events', function ($app) {
        return (new Dispatcher($app))->setQueueResolver(function () use ($app) {
            return $app->make(QueueFactoryContract::class);
        });
    });
}

承接上一步,从容器对象调用事件服务中的 register 方法,实现控制反转

$this->app 返回容器对象,然后调用容器对象中的 singleton,传入一个 'events' 字符串和一个闭包函数,记住未执行的闭包函数哦

下一步,看一下容器中的 singleton 方法,如何处理控制反转过来的参数

Step.046--项目根目录/vendor/laravel/framework/src/Illuminate/Container/Container.php #345

public function singleton($abstract, $concrete = null)
{  // $abstract: "events"; $concrete: 闭包对象
    $this->bind($abstract, $concrete, true);
}

承接上一步,调用 bind 方法

下一步,看一下 bind 方法执行

Step.047--项目根目录/vendor/laravel/framework/src/Illuminate/Container/Container.php #214

public function bind($abstract, $concrete = null, $shared = false)
{ // $abstract: "events"; $concrete: 闭包对象; $shared: false
    // 从容器中,删除之前以 events 为键的数值对
    $this->dropStaleInstances($abstract);
    // 如果没有传闭包进来,则 $abstract 赋值给 $concrete
    if (is_null($concrete)) {
        $concrete = $abstract;
    }

    // 如果 $concrete 不是闭包对象,则执行里面的代码,获取一个闭包
    if (! $concrete instanceof Closure) {
        $concrete = $this->getClosure($abstract, $concrete);
    }

    // 主要!以 $abstract 为键,$concrete 和 $shared 合并的关联数组为值,叠加到 bindings 属性上
    $this->bindings[$abstract] = compact('concrete', 'shared');

    // 根据 $abstract 或其别名查看 `resolved` 属性和 `instances` 属性有没有赋值过 $abstract 或其别名,有则执行里面的代码
    if ($this->resolved($abstract)) {
        $this->rebound($abstract);
    }
}

承接上一步,调用 bind 方法,将摘要和生成实例的闭包对象绑定到 bindings 属性上去

下一步,看一下 dropStaleInstances 方法执行

Step.048--项目根目录/vendor/laravel/framework/src/Illuminate/Container/Container.php #1126

protected function dropStaleInstances($abstract)
{  // $abstract: "events"
    unset($this->instances[$abstract], $this->aliases[$abstract]);
}

承接上一步,销毁 $this->instances[$abstract] 和 $this->aliases[$abstract]

由于 $concrete 是闭包对象,所以前两个 if 都不执行

返回到第 41 步的 $provider->register() 方法,继续向下执行

由于事件对象不存在 bindings 和 singletons 属性,所以接下来的两个 if 都不执行

由于第一次运行,故 $this->resolved($abstract) 返回 false

下一步,看一下 $this->markAsRegistered($provider);

Step.049--项目根目录/vendor/laravel/framework/src/Illuminate/Foundation/Application.php #646

protected function markAsRegistered($provider)
{  // $provider: 事件服务对象
    $this->serviceProviders[] = $provider;

    $this->loadedProviders[get_class($provider)] = true;
}

承接上一步,记录注册的事件服务对象

可以返回到第 39 步,由于注册日志服务和路由服务大同小异,直接执行完毕。上图看变量

Laravel 之道第四章:步调 Laravel 容器 Application 的初始化

你可能疑问,为什么 bindings 属性这么多,我记得只有三个呀。那是应为路由服务对象,反向注册了多个闭包对象

我们看一下路由服务提供者的 register 方法

public function register()
{
    $this->registerRouter();  // 注册路由服务
    $this->registerUrlGenerator();  // 注册URL生成器服务
    $this->registerRedirector();  // 注册重定向服务
    $this->registerPsrRequest();  // 注册Psr的request服务
    $this->registerPsrResponse();  // 注册Psr的Response服务
    $this->registerResponseFactory();  // 注册response工厂服务
    $this->registerControllerDispatcher();  // 注册控制器迪调控服务
}

下一步,我看一下 $this->registerCoreContainerAliases();, 初始化的最后一步

Step.050--项目根目录/vendor/laravel/framework/src/Illuminate/Foundation/Application.php #1075

public function registerCoreContainerAliases()
{
    foreach ([
        'app'                  => [\Illuminate\Foundation\Application::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],
        'blade.compiler'       => [\Illuminate\View\Compilers\BladeCompiler::class],
        'cache'                => [\Illuminate\Cache\CacheManager::class, \Illuminate\Contracts\Cache\Factory::class],
        'cache.store'          => [\Illuminate\Cache\Repository::class, \Illuminate\Contracts\Cache\Repository::class],
        'config'               => [\Illuminate\Config\Repository::class, \Illuminate\Contracts\Config\Repository::class],
        'cookie'               => [\Illuminate\Cookie\CookieJar::class, \Illuminate\Contracts\Cookie\Factory::class, \Illuminate\Contracts\Cookie\QueueingFactory::class],
        'encrypter'            => [\Illuminate\Encryption\Encrypter::class, \Illuminate\Contracts\Encryption\Encrypter::class],
        'db'                   => [\Illuminate\Database\DatabaseManager::class],
        'db.connection'        => [\Illuminate\Database\Connection::class, \Illuminate\Database\ConnectionInterface::class],
        'events'               => [\Illuminate\Events\Dispatcher::class, \Illuminate\Contracts\Events\Dispatcher::class],
        'files'                => [\Illuminate\Filesystem\Filesystem::class],
        'filesystem'           => [\Illuminate\Filesystem\FilesystemManager::class, \Illuminate\Contracts\Filesystem\Factory::class],
        'filesystem.disk'      => [\Illuminate\Contracts\Filesystem\Filesystem::class],
        'filesystem.cloud'     => [\Illuminate\Contracts\Filesystem\Cloud::class],
        'hash'                 => [\Illuminate\Hashing\HashManager::class],
        'hash.driver'          => [\Illuminate\Contracts\Hashing\Hasher::class],
        'translator'           => [\Illuminate\Translation\Translator::class, \Illuminate\Contracts\Translation\Translator::class],
        'log'                  => [\Illuminate\Log\LogManager::class, \Psr\Log\LoggerInterface::class],
        'mailer'               => [\Illuminate\Mail\Mailer::class, \Illuminate\Contracts\Mail\Mailer::class, \Illuminate\Contracts\Mail\MailQueue::class],
        'auth.password'        => [\Illuminate\Auth\Passwords\PasswordBrokerManager::class, \Illuminate\Contracts\Auth\PasswordBrokerFactory::class],
        'auth.password.broker' => [\Illuminate\Auth\Passwords\PasswordBroker::class, \Illuminate\Contracts\Auth\PasswordBroker::class],
        'queue'                => [\Illuminate\Queue\QueueManager::class, \Illuminate\Contracts\Queue\Factory::class, \Illuminate\Contracts\Queue\Monitor::class],
        'queue.connection'     => [\Illuminate\Contracts\Queue\Queue::class],
        'queue.failer'         => [\Illuminate\Queue\Failed\FailedJobProviderInterface::class],
        'redirect'             => [\Illuminate\Routing\Redirector::class],
        'redis'                => [\Illuminate\Redis\RedisManager::class, \Illuminate\Contracts\Redis\Factory::class],
        'request'              => [\Illuminate\Http\Request::class, \Symfony\Component\HttpFoundation\Request::class],
        'router'               => [\Illuminate\Routing\Router::class, \Illuminate\Contracts\Routing\Registrar::class, \Illuminate\Contracts\Routing\BindingRegistrar::class],
        'session'              => [\Illuminate\Session\SessionManager::class],
        'session.store'        => [\Illuminate\Session\Store::class, \Illuminate\Contracts\Session\Session::class],
        'url'                  => [\Illuminate\Routing\UrlGenerator::class, \Illuminate\Contracts\Routing\UrlGenerator::class],
        'validator'            => [\Illuminate\Validation\Factory::class, \Illuminate\Contracts\Validation\Factory::class],
        'view'                 => [\Illuminate\View\Factory::class, \Illuminate\Contracts\View\Factory::class],
    ] as $key => $aliases) {
        foreach ($aliases as $alias) {
            $this->alias($key, $alias);
        }
    }
}

承接上一步,执行核心别名注册

上面进行两层 foreach 循环,把数组中的键和值中值,赋值到容器对象的 aliases 和 abstractAliases 属性中

看一下 alias 方法

public function alias($abstract, $alias)
{
    $this->aliases[$alias] = $abstract;

    $this->abstractAliases[$abstract][] = $alias;
}

这段代码,就是简单是属性数组叠加赋值

现在执行完毕,看一下数据

Laravel 之道第四章:步调 Laravel 容器 Application 的初始化

Laravel 之道第四章:步调 Laravel 容器 Application 的初始化

下一步,返回到 项目根目录/bootstrap/app.php 中,将初始化好的容器对象赋值给 $app

本文章首发在 Laravel China 社区

我们是一群被时空压迫的孩子。 ---- 爱因斯坦

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。

Algorithms and Data Structures

Algorithms and Data Structures

Kurt Mehlhorn、Peter Sanders / Springer / 2008-08-06 / USD 49.95

Algorithms are at the heart of every nontrivial computer application, and algorithmics is a modern and active area of computer science. Every computer scientist and every professional programmer shoul......一起来看看 《Algorithms and Data Structures》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具