版权声明:本文为博主原创文章,未经博主允许不得转载。

紧接上一篇

$app->withFacades();//为应用程序注册门面。

$app->withEloquent();//为应用程序加载功能强大的库。

先来看看withFacades()

/**
* Register the facades for the application.(为应用程序注册门面。)
*
* @param bool $aliases
* @param array $userAliases
* @return void
*/
public function withFacades($aliases = true, $userAliases = [])
{
Facade::setFacadeApplication($this); if ($aliases) {
$this->withAliases($userAliases);
}
}
setFacadeApplication()
    /**
* Set the application instance.(设置应用程序实例。)
*
* @param \Illuminate\Contracts\Foundation\Application $app
* @return void
*/
public static function setFacadeApplication($app)
{
static::$app = $app;
}

将当前实例传给门面类(Facade)

$this->withAliases($userAliases)

    /**
* Register the aliases for the application.(注册应用程序的别名。)
*
* @param array $userAliases
* @return void
*/
public function withAliases($userAliases = [])
{
$defaults = [
'Illuminate\Support\Facades\Auth' => 'Auth',
'Illuminate\Support\Facades\Cache' => 'Cache',
'Illuminate\Support\Facades\DB' => 'DB',
'Illuminate\Support\Facades\Event' => 'Event',
'Illuminate\Support\Facades\Gate' => 'Gate',
'Illuminate\Support\Facades\Log' => 'Log',
'Illuminate\Support\Facades\Queue' => 'Queue',
'Illuminate\Support\Facades\Schema' => 'Schema',
'Illuminate\Support\Facades\URL' => 'URL',
'Illuminate\Support\Facades\Validator' => 'Validator',
]; if (! static::$aliasesRegistered) {//判断是否已注册类别名。
static::$aliasesRegistered = true; $merged = array_merge($defaults, $userAliases); foreach ($merged as $original => $alias) {
class_alias($original, $alias);//设置别名
}
}
}

然后就是withEloquent()函数

    /**
* Load the Eloquent library for the application.(为应用程序加载功能强大的库。)
*
* @return void
*/
public function withEloquent()
{
$this->make('db');
}

  

    /**
* Resolve the given type from the container.(从容器中解析给定类型。)
*
* @param string $abstract
* @return mixed
*/
public function make($abstract)
{
$abstract = $this->getAlias($abstract); if (array_key_exists($abstract, $this->availableBindings) &&
! array_key_exists($this->availableBindings[$abstract], $this->ranServiceBinders)) {
$this->{$method = $this->availableBindings[$abstract]}(); $this->ranServiceBinders[$method] = true;
} return parent::make($abstract);
}

一步一步来,make()函数以后经常用得上。

    /**
* Get the alias for an abstract if available.(如果可用的话,获取抽象的别名。)
*
* @param string $abstract
* @return string
*
* @throws \LogicException
*/
public function getAlias($abstract)
{
if (! isset($this->aliases[$abstract])) {  //$this->aliases是注册类别名,如果没有别名,则直接返回$abstract
return $abstract;
} if ($this->aliases[$abstract] === $abstract) {  //如果$abstract是别名本身,则会抛出异常
throw new LogicException("[{$abstract}] is aliased to itself.");
} return $this->getAlias($this->aliases[$abstract]);
}

这一个的$this->aliases的值来着上一篇文章registerContainerAliases()函数对它的赋值

接下来是这段

    if (array_key_exists($abstract, $this->availableBindings) &&
! array_key_exists($this->availableBindings[$abstract], $this->ranServiceBinders)) {
$this->{$method = $this->availableBindings[$abstract]}(); $this->ranServiceBinders[$method] = true;
}
$this->availableBindings变量在Applilcation类的定义是是
    /**
* The available container bindings and their respective load methods.(可用的容器绑定及其各自的加载方法。)
*
* @var array
*/
public $availableBindings = [
'auth' => 'registerAuthBindings',
'auth.driver' => 'registerAuthBindings',
'Illuminate\Auth\AuthManager' => 'registerAuthBindings',
'Illuminate\Contracts\Auth\Guard' => 'registerAuthBindings',
'Illuminate\Contracts\Auth\Access\Gate' => 'registerAuthBindings',
'Illuminate\Contracts\Broadcasting\Broadcaster' => 'registerBroadcastingBindings',
'Illuminate\Contracts\Broadcasting\Factory' => 'registerBroadcastingBindings',
'Illuminate\Contracts\Bus\Dispatcher' => 'registerBusBindings',
'cache' => 'registerCacheBindings',
'cache.store' => 'registerCacheBindings',
'Illuminate\Contracts\Cache\Factory' => 'registerCacheBindings',
'Illuminate\Contracts\Cache\Repository' => 'registerCacheBindings',
'composer' => 'registerComposerBindings',
'config' => 'registerConfigBindings',
'db' => 'registerDatabaseBindings',
'Illuminate\Database\Eloquent\Factory' => 'registerDatabaseBindings',
'encrypter' => 'registerEncrypterBindings',
'Illuminate\Contracts\Encryption\Encrypter' => 'registerEncrypterBindings',
'events' => 'registerEventBindings',
'Illuminate\Contracts\Events\Dispatcher' => 'registerEventBindings',
'files' => 'registerFilesBindings',
'hash' => 'registerHashBindings',
'Illuminate\Contracts\Hashing\Hasher' => 'registerHashBindings',
'log' => 'registerLogBindings',
'Psr\Log\LoggerInterface' => 'registerLogBindings',
'queue' => 'registerQueueBindings',
'queue.connection' => 'registerQueueBindings',
'Illuminate\Contracts\Queue\Factory' => 'registerQueueBindings',
'Illuminate\Contracts\Queue\Queue' => 'registerQueueBindings',
'Psr\Http\Message\ServerRequestInterface' => 'registerPsrRequestBindings',
'Psr\Http\Message\ResponseInterface' => 'registerPsrResponseBindings',
'translator' => 'registerTranslationBindings',
'url' => 'registerUrlGeneratorBindings',
'validator' => 'registerValidatorBindings',
'Illuminate\Contracts\Validation\Factory' => 'registerValidatorBindings',
'view' => 'registerViewBindings',
'Illuminate\Contracts\View\Factory' => 'registerViewBindings',
];
$this->ranServiceBinders变量是记录已执行的服务绑定方法。
当前执行的是make('db'),所以$abstract=‘db’;
$this->availableBindings['db'] = 'registerDatabaseBindings';
$this->{$method = $this->availableBindings[$abstract]}();

会执行到Application的registerDatabaseBindings方法

    /**
* Register container bindings for the application.(为应用程序注册容器绑定。)
*
* @return void
*/
protected function registerDatabaseBindings()
{
$this->singleton('db', function () {  //这里是用闭包函数注册一个db的单例
return $this->loadComponent(
'database', [
'Illuminate\Database\DatabaseServiceProvider',
'Illuminate\Pagination\PaginationServiceProvider',
], 'db'
);
});
}
这里是用闭包函数注册一个db的单例,接着看闭包内执行了什么
    /**
* Configure and load the given component and provider.(配置并加载给定的组件和提供程序。)
*
* @param string $config
* @param array|string $providers
* @param string|null $return
* @return mixed
*/
public function loadComponent($config, $providers, $return = null)
{
$this->configure($config);//将配置文件加载到应用程序中。 foreach ((array) $providers as $provider) {
$this->register($provider);//注册传过来的服务供应类
} return $this->make($return ?: $config);//
}
因为这里第一次初始化后,$this->ranServiceBinders[$method]=true,所以以后调用db时,都会直接调用父类(Container)的make()函数。
讲远了的感觉,不过刚好可以一起讲一下最后一步return parent::make($abstract);
    /**
* Resolve the given type from the container.
*
* @param string $abstract
* @return mixed
*/
public function make($abstract)
{
return $this->resolve($abstract);
}

Container类的make()只调用了$this->resolve()函数,马不停蹄,我们来看看这个函数

/**
* Resolve the given type from the container.(从容器中解析给定类型。)
*
* @param string $abstract
* @param array $parameters
* @return mixed
*/
protected function resolve($abstract, $parameters = [])
{
$abstract = $this->getAlias($abstract);//取实际类名 $needsContextualBuild = ! empty($parameters) || ! is_null(
$this->getContextualConcrete($abstract)
); //如果该类型的实例目前作为单例管理,
//我们将只返回一个现有的实例而不是实例化新的实例,
//所以开发人员每次都可以继续使用同一个对象实例。
if (isset($this->instances[$abstract]) && ! $needsContextualBuild) {  //单例已存在直接返回
return $this->instances[$abstract];
} $this->with[] = $parameters; $concrete = $this->getConcrete($abstract);  //返回给定抽象的具体类型(包括一些关于上下文的绑定操作) //我们已经准备好实例化绑定注册的具体类型的实例。
//这将实例化类型,以及递归地解析所有的“嵌套”依赖关系,直到所有问题都得到解决为止。
if ($this->isBuildable($concrete, $abstract)) {  //判断是否为递归
$object = $this->build($concrete);  //递归用build(),用make()会死循环
} else {
$object = $this->make($concrete);   //非递归用make()
} //如果我们定义了这种类型的扩展程序,
//我们需要将它们旋转并将它们应用到正在构建的对象中。
//这允许扩展服务,例如更改配置或装饰对象。
foreach ($this->getExtenders($abstract) as $extender) {  //执行扩展
$object = $extender($object, $this);
} //如果请求的类型被注册为单例,我们将缓存“内存”中的实例,
//以便稍后返回它,而不必为每一个后续请求创建一个对象的全新实例。
if ($this->isShared($abstract) && ! $needsContextualBuild) {
$this->instances[$abstract] = $object;
} $this->fireResolvingCallbacks($abstract, $object);  //回调 //返回之前,我们还将解析的标志设置为“true”,
//并弹出此构建的参数重写。完成这两件事后,我们将准备返回完全构造的类实例。
$this->resolved[$abstract] = true; array_pop($this->with);  //移除最后一个键值,也就是$this->with[] = $parameters;
     return $object; 
}

这里是整篇文比较难的地方,部分注释是直译的,讲了这么久,其实也执行了$app->withFacades()和$app->withEloquent();

其实后面的一些注册和绑定与前面也是类似的,希望能帮到大家!

Lumen技术交流群:310493206

版权声明:本文为博主原创文章,未经博主允许不得转载。

Lumen开发:lumen源码解读之初始化(2)——门面(Facades)与数据库(db)的更多相关文章

  1. Lumen开发:lumen源码解读之初始化(4)——服务提供(ServiceProviders)与路由(Routes)

    版权声明:本文为博主原创文章,未经博主允许不得转载. 前面讲了singleton和Middleware,现在来继续讲ServiceProviders和Routes,还是看起始文件bootstrap/a ...

  2. mybatis源码解读(一)——初始化环境

    本系列博客将对mybatis的源码进行解读,关于mybatis的使用教程,可以查看我前面写的博客——传送门. 为了便于后面的讲解,我们这里首先构造一个统一环境.也可以参考mybatis官网. 1.数据 ...

  3. Lumen开发:lumen源码解读之初始化(3)——单例(singleton)与中间件(Middleware)

    版权声明:本文为博主原创文章,未经博主允许不得转载. 今天来讲讲Lumen的singleton和Middleware,先来看看起始文件bootstrap/app.php / * | --------- ...

  4. Lumen开发:lumen源码解读之初始化(5)——注册(register)与启动(boot)

    版权声明:本文为博主原创文章,未经博主允许不得转载. register()是在服务容器注册服务, bootstrap/app.php /** * 注册外部服务 */ $app->register ...

  5. Lumen开发:lumen源码解读之初始化(1)——app实例

    版权声明:本文为博主原创文章,未经博主允许不得转载. 有些注释来着原文的百度翻译,可以有些难理解或者奇怪,我后面会根据自己的理解做调整的哈!!!不喜勿喷,层主英语不过关... 先来看看入口文件publ ...

  6. Vue 源码解读(2)—— Vue 初始化过程

    当学习成为了习惯,知识也就变成了常识. 感谢各位的 点赞.收藏和评论. 新视频和文章会第一时间在微信公众号发送,欢迎关注:李永宁lyn 文章已收录到 github 仓库 liyongning/blog ...

  7. Spark jdbc postgresql数据库连接和写入操作源码解读

    概述:Spark postgresql jdbc 数据库连接和写入操作源码解读,详细记录了SparkSQL对数据库的操作,通过java程序,在本地开发和运行.整体为,Spark建立数据库连接,读取数据 ...

  8. SDWebImage源码解读之SDWebImageDownloaderOperation

    第七篇 前言 本篇文章主要讲解下载操作的相关知识,SDWebImageDownloaderOperation的主要任务是把一张图片从服务器下载到内存中.下载数据并不难,如何对下载这一系列的任务进行设计 ...

  9. SDWebImage源码解读之SDWebImageCache(上)

    第五篇 前言 本篇主要讲解图片缓存类的知识,虽然只涉及了图片方面的缓存的设计,但思想同样适用于别的方面的设计.在架构上来说,缓存算是存储设计的一部分.我们把各种不同的存储内容按照功能进行切割后,图片缓 ...

随机推荐

  1. 【Git】windows上git命令中文乱码的问题

    windows上git命令中文乱码的问题解决 1.打开git bash快捷方式启动 2.右键 options 3.进入text选项卡,选中中文 和UTF-8 4.应用 测试[中文正常显示] 尝试打开文 ...

  2. sharepoint2010新建网站与网站集

    1.以管理员身份运行[sharepoint管理中心] 2.点击创建web应用程序 3.切换用户,我的个人用户不行,需要切换administrator用户 可以看到换成administrator账号 新 ...

  3. 控制面板cpl大全

    ALSNDMGR.CPL AC97 Audio组态设定appwiz.cpl 添加和删除程序bthprops.cpldesk.cpl   显示属性firewall.cpl Windows防火墙hdwwi ...

  4. 关于C++中_finite()函数的说明 [转]

    The function int _finite(double x) returns 1 (true) if x is an ordinary number and 0 (false) if x is ...

  5. 小白学react之网页获取微信用户信息

    通过上一篇<小白学react之EJS模版实战>我们学习了怎样通过EJS模版生成我们高定制化的index.html文件. 本篇我们将会继续延续我们的alt-tutorial项目的实战计划.去 ...

  6. mysql ubuntu 开启3306端口,设置远程访问

    远程登陆数据库的时候出现了下面出错信息 :ERROR 2003 ( HY000 ) : Can 't connect to MySQL server on ' xxx.xxx.xxx.xxx ',经过 ...

  7. VM虚拟机 Windows虚拟机中linux鼠标不能动怎么办

    有一次vmware安装red hat linux后,进入x-windows界面,鼠标不能用,百思不得其解,因为自己的安装linux的过程中设置绝对是没有问题的啊,鼠标设置肯定是usb带滑轮,这个肯定没 ...

  8. IOS开发通过代码方式使用AutoLayout (NSLayoutConstraint + Masonry) 转载

    http://blog.csdn.net/he_jiabin/article/details/48677911 随着iPhone6/6+设备的上市,如何让手头上的APP适配多种机型多种屏幕尺寸变得尤为 ...

  9. Oracle PLSQL通过SMTP发送E-MAIL邮件代码

    登录到SMTPserver发送邮件,支持HTML CREATE OR REPLACE PROCEDURE send_mail(        p_recipient VARCHAR2, -- 邮件接收 ...

  10. Win10 导航窗口不能移动文件win10 资源管理器 无法拖动文件到左侧驱动器

    Win10 导航窗口不能移动文件怎么办 Win10左侧导航栏不能移动文件怎么办 win10 资源管理器 无法拖动文件到左侧驱动器怎么办 在同一个文件夹可以拖动来移动文件,拖到地址栏的面包屑也可以移动文 ...