Lumen开发:lumen源码解读之初始化(2)——门面(Facades)与数据库(db)
版权声明:本文为博主原创文章,未经博主允许不得转载。
紧接上一篇
1 2 3 | $app ->withFacades(); //为应用程序注册门面。 $app ->withEloquent(); //为应用程序加载功能强大的库。 |
先来看看withFacades()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | /** * 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 ); } } |
1 | setFacadeApplication() |
1 2 3 4 5 6 7 8 9 10 | /** * Set the application instance.(设置应用程序实例。) * * @param \Illuminate\Contracts\Foundation\Application $app * @return void */ public static function setFacadeApplication( $app ) { static :: $app = $app ; } |
将当前实例传给门面类(Facade)
$this->withAliases($userAliases)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | /** * 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()函数
1 2 3 4 5 6 7 8 9 | /** * Load the Eloquent library for the application.(为应用程序加载功能强大的库。) * * @return void */ public function withEloquent() { $this ->make( 'db' ); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /** * 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()函数以后经常用得上。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /** * 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()函数对它的赋值
接下来是这段
1 2 3 4 5 6 | if ( array_key_exists ( $abstract , $this ->availableBindings) && ! array_key_exists ( $this ->availableBindings[ $abstract ], $this ->ranServiceBinders)) { $this ->{ $method = $this ->availableBindings[ $abstract ]}(); $this ->ranServiceBinders[ $method ] = true; } |
1 | $this ->availableBindings变量在Applilcation类的定义是是 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | /** * 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' , ]; |
1 | <br> $this ->ranServiceBinders变量是记录已执行的服务绑定方法。 |
1 | 当前执行的是make( 'db' ),所以 $abstract =‘db’; |
1 2 | $this ->availableBindings[ 'db' ] = 'registerDatabaseBindings' ; $this ->{ $method = $this ->availableBindings[ $abstract ]}(); |
会执行到Application的registerDatabaseBindings方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | /** * 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' ); }); } |
1 | 这里是用闭包函数注册一个db的单例,接着看闭包内执行了什么 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | /** * 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 ); // } |
1 | 因为这里第一次初始化后, $this ->ranServiceBinders[ $method ]=true,所以以后调用db时,都会直接调用父类(Container)的make()函数。 |
1 | 讲远了的感觉,不过刚好可以一起讲一下最后一步 return parent::make( $abstract ); |
1 2 3 4 5 6 7 8 9 10 | /** * Resolve the given type from the container. * * @param string $abstract * @return mixed */ public function make( $abstract ) { return $this ->resolve( $abstract ); } |
Container类的make()只调用了$this->resolve()函数,马不停蹄,我们来看看这个函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | /** * 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; <br>} |
这里是整篇文比较难的地方,部分注释是直译的,讲了这么久,其实也执行了$app->withFacades()和$app->withEloquent();
其实后面的一些注册和绑定与前面也是类似的,希望能帮到大家!
Lumen技术交流群:310493206
版权声明:本文为博主原创文章,未经博主允许不得转载。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· 因为Apifox不支持离线,我果断选择了Apipost!