加载composer 的自动加载器,支持了PSR-0 PSR-4
1 | require(__DIR__ . '/../vendor/autoload.php'); |
进行常量的定义,并且声明了最基本的方法例如getVersion
1 | require __DIR__ . '/BaseYii.php'; |
加载Yii自己的autoload加载器,从classmap中寻找,指定的类,如果没有找到,会解析名称到路径。
1 | spl_autoload_register(['Yii', 'autoload'], true, true); |
todo 容器生成
1 | Yii::$container = new yii\di\Container(); |
开始生成一个应用主体,并且加载了config配置,直接运行
1 | (new yii\web\Application($config))->run(); |
主体生成
application is the base class for all web application classes.
Yii::$app
是应用主体的实例,一个请求只会生成一个应用主体
在Application
类中,定义了初始的defaultRoute
,以及coreComponent
核心组件的列表,还有一些请求和相应相关的方法
继承链
1 | web/application`=>`base/application`=>`base/Model`=>`id/ServiceLocator`=>`base/component`=>`base/object`=>`base/configurable |
初始化主体的配置
1 | public function __construct($config = []) |
其中preInit会进行一个注册核心组件,这里web的入口进行了扩展,包含了request等
1 | public function coreComponents() |
讲configure格式为对象,存储到应用主体中
1 | public function __construct($config = []) |
组件注册
这里我们来看下组件是如何注册到应用主体中的,这个->
实际上调用的是__Set
魔术方法,
那我们再看这个$this
是什么,很明显是指yii\web\application
1 | public static function configure($object, $properties) |
我们从webapplication向parent一层一层的找,找到了__set 的定义,在basecomponent
1 | public function __set($name, $value) |
上面的set方法,会遍历config的属性,来交给不同的set方法处理,果然恰好存在了一个setComponents
,用来处理组件
1 | public function setComponents($components) |
最终组件配置就这样被注册到了$this->_definitions
里面,后面我们可以通过$this->get($id)
来获取组件配置
1 | public function set($id, $definition) |
注意这个init,并不是当前类下面的init方法,而是被webapplication 覆盖
1 | public function init() |
同样bootstrap方法也被覆盖
1 | protected function bootstrap() |
看下getRequest是怎么回事,跟踪代码,它通过get方法,来从_definitions中获取request
对应的配置
然后根据配置中的yiiwebrequest 来进行创建对象,其中$type 就是配置
1 | public static function createObject($type, array $params = []) |
进行完web层的引导之后,继续进行base层的引导,包括对配置中bootstrap的引导注册,会直接通过容器得到实例。(具体不详)
小结
在上面的new的过程中,完成了组件的注册,配置的初始化,并且学到了get是createObject通过依赖注入的方法,获取组件对象
请求的处理
前面所有的配置和准备都初始化完毕之后,要进行请求处理了。
这一句的run方法,就是处理请求的整个启动入口
1 | $application->run(); |
使用handleRequest方法来处理请求,并且参数是request实例,其中handleRequest方法要看webapplication层的封装
1 | $response = $this->handleRequest($this->getRequest()); |
调用resolve进行解析
1 | list($route, $params) = $request->resolve(); |
我们再看Urlmanager的时候,发现里面定义的routeParam是r也就是默认接受参数的值(重要)
实际上下面这段代码完成的就是解析了$_GET的值,从里面寻找routeParam 定义的值(r)所代表的内容
1 | $result = Yii::$app->getUrlManager()->parseRequest($this); |
这里要调用action方法了
1 | $this->requestedRoute = $route; |
创建控制器+调用action
实际上runAction中的主要内容就是createController
的实现:
1 | // parts 分为两部分,0 是controller的实例,1 是实例里面的方法名称 |
如果遇到了控制器,那么直接返回控制器对象和方法route的名称,这里route类似于action方法名称,代码略微繁琐,但是很清晰,具体实现就是
路由解析规则
例如r=site
- 寻找controller,找到site控制器,直接实例化
例如r=site/index
- 构造控制器,并且id为site、route为index
例如r=site/index/test
- 发现没有找到控制器,那么从模块中获取,这里是重新构造id为site/index route为test,然后调用
createControllerById
方法来获取控制器(具体不详,不过应该是通过namespace定位了)
而且createController
直接返回了controller的实例
然后我们在createAction
中找到解析action方法名称的代码
例如r=site/index-test 那么下面对应的methodName就是actionIndexTest
1 | $methodName = 'action' . str_replace(' ', '', ucwords(implode(' ', explode('-', $id)))); |
内容输出
将调用action方法的值,进行返回,然后直接交给yii\web\Response
作为data属性的一部分。最后调用send方法,进行输出。
1 | public function send() |
行为是如何注册到组件的呢?
通过attacheBehavior
注册行为之后,实际上是添加到了$this
的_behaviors
属性中
那么行为中的属性,就添加到了,_behaviors
中
进行直接调用行为里面的方法的时候,实际上触发了yii\base\Component
里面的__call
魔术方法