这个要启用后面很长一段时间来解析一下laravel源码,当然这也是一个浩大工程。可能至少要好几个月。当然这也是一个很好的学习机会
前提
我是基于laravel5.4.30+php7.1+mac
laravel 单入口文件
现在所有的框架都基于单入口,那么laravel框架的但入口文件在哪呢,当然
public/index.php
,那么简单来看一下这个文件
//composer 这个也是一个大块头,暂时只要知道他可以自动加载类库就可以了,后面单独在分析require __DIR__.'/../bootstrap/autoload.php';//这个地方就是实例化Application 的过程$app = require_once __DIR__.'/../bootstrap/app.php';... //后面代码省略
那么我们看一下bootstrap/app.php
这个文件,代码:
//为laravel创建了一个实例容积,以后的laravel 的所有主见都会放在这个实例容器里$app = new Illuminate\Foundation\Application( realpath(__DIR__.'/../'));
Illuminate\Foundation\Application
继承Illuminate\Container\Container
,这个有什么用呢,后面看,简单看一下Application
:
//构造函数 public function __construct($basePath = null) { //注册一堆框架的目录,最后都会变成$this->instances 里面的东西,如图一 if ($basePath) { $this->setBasePath($basePath); } //把application 自己绑定到自己的变量$instances中 $this->registerBaseBindings(); //注册框架一些基层服务 $this->registerBaseServiceProviders(); //注册核心类的别名 $this->registerCoreContainerAliases(); } //注册app protected function registerBaseBindings() { //上面说了Application 继承了Container这个使用了static::,静态延迟绑定,说面这个方法在Container 里,这个方法其实就是把Application 实例赋值到 static::$instance static::setInstance($this); //注册一个实例到容器中,这个就变成了 $this->instances['app']=application实例 $this->instance('app', $this); //这个其实和上面也是一下的,$this->instances['"Illuminate\Container\Container"]=Application 实例 $this->instance(Container::class, $this); } /** * 绑定实例到容器中的instances 中 */ public function instance($abstract, $instance) { $this->removeAbstractAlias($abstract); $isBound = $this->bound($abstract); unset($this->aliases[$abstract]); $this->instances[$abstract] = $instance; if ($isBound) { $this->rebound($abstract); } }
【图一】其实在
__construct
有四个步骤: 注册全局路径
注册自身
注册基层服务
注册别名
其实注册基层服务重点
基层服务
我们看一下 $this->registerBaseServiceProviders()
这个步骤干了什么:
/** * 绑定所有的基础服务 */ protected function registerBaseServiceProviders() { //注册事件服务 $this->register(new EventServiceProvider($this)); //日志服务 $this->register(new LogServiceProvider($this)); //路由服务,这个里面注册了很多东西,从图二可以看出来,路由以后单独分析 $this->register(new RoutingServiceProvider($this)); //最后他们的实例都在 $this->bindings 里面, 如图二 } public function register($provider, $options = [], $force = false) { .... //可以看到这个地方随带启动上面几个 服务的 `register` 方法 if (method_exists($provider, 'register')) { $provider->register(); } //把注册的服务放到$this->serviceProviders 并在$this->loadedProviders 中标记,保证下一次不会从新注册 $this->markAsRegistered($provider); .... } protected function markAsRegistered($provider) { $this->serviceProviders[] = $provider; $this->loadedProviders[get_class($provider)] = true; }
接下来就是$this->registerCoreContainerAliases()
,看下代码:
public function registerCoreContainerAliases() { //仔细看一下,这些数据就会一个有规律,数组都是接口和这个接口实例,这也就是laravel 里的contracts foreach ([ 'app' => [\Illuminate\Foundation\Application::class, \Illuminate\Contracts\Container\Container::class, \Illuminate\Contracts\Foundation\Application::class], //..... 省略 ] as $key => $aliases) { foreach ($aliases as $alias) { $this->alias($key, $alias); } } } //可以看到这些类的 public function alias($abstract, $alias) { $this->aliases[$alias] = $abstract; //如图三 $this->abstractAliases[$abstract][] = $alias; //如图四 }
【图三】【图四】
之后返回了一个Application 实例,这一步算是完成了,也就是说bootstrap/app.php
的第一行代码就是本文的内容了,当然熟悉laravel 的朋友可能看出来,我把serverProvider
中的boot
给漏掉了,那是因为那里设计到php的反射,那也是可以单独拿出来的一个版块,后面再说