Home  >  Article  >  Backend Development  >  Source code analysis of YII (-)

Source code analysis of YII (-)

WBOY
WBOYOriginal
2016-08-08 09:33:001198browse

As my first source code analysis, I picked yii (pronounced as waiyiyi instead of waiaiai); I won’t say more about its praise and go straight to the point. Prepare materials first. It is recommended to download the latest version of yii source code package (1.1.15) directly from the official website.

There is the simplest application in the demos - helloworld. It uses the yii framework to output a sentence: "hello world";

I will start from it, analyze the components that the framework goes through to execute a minimum process, and briefly analyze its operation process.

Start reading from the single entry document. (The source code is generally analyzed starting from the call point)

Index.php->

//include Yii bootstrap file

//Introduce startup file

require_once(dirname(__FILE__).'/../../framework/yii.php');

yii.php ->

//YiiBase is a helper class serving common framework functionalities.

//YiiBase is a helper class that serves the entire framework. Many important constants are defined here

require(dirname(__FILE__).'/YiiBase.php');

//Register automatic loading class

spl_autoload_register(array('YiiBase','autoload'));

//Import interface class

require(YII_PATH.'/base/interfaces.php');

//Start the application

Yii::createWebApplication()->run();

The code seems to end here, and the content of the page is also displayed, but we have no idea what the framework does. So we need to break this step down and expose the details inside.

Yii::createWebApplication()->run() can be divided into three parts

  1. Yii
  2. createWebApplication
  3. run

Yii What is this thing?

You can find this line of code from yii.php class Yii extends YiiBase

It means that it is the inherited class of YiiBase, and the author's extension is left blank, so Yii is just a reference to YiiBase. Therefore, the static method createWebApplication also has to be found in YiiBase.

In YiiBase.php, it’s easy to find this method:

public static function createWebApplication($config=null)

                                                                    

                                                                                    return self::createApplication('CWebApplication',$config);

         }

It passes the task to createApplication again:

​​​​​​ public static function createApplication($class,$config=null)

                                                                   

                                                                                return new $class($config);

          }

Combined, createWebApplication () is return new CWebApplication($config);

Where is this CWebApplication class? How was it introduced?

With a series of questions, I returned to YiiBase.php

A very long array is defined there, you can find:

'CWebApplication' => '/web/CWebApplication.php', this is a member of the autoloading class

For how it implements automatic loading, you can view the relevant documents of spl_autoload_register, but here is an extraneous detail.

Let’s continue to dig deeper into CWebApplication. Open the file /web/CWebApplication.php.

As mentioned earlier, return new CWebApplication($config); according to my experience, when using new, there is usually a constructor, but I did not find its constructor. It must be in its parent class, so I searched higher and found class CWebApplication extends CApplication. It was like digging for a loach. I had to follow the clues and find them bit by bit. I had to be patient.

There is indeed a constructor in CApplication, the code is as follows:

<spanmicrosoft yahei font-size:><span>public</span> <span>function</span> __construct(<span>$config</span>=<span>null</span><span>)

         {

                   Yii</span>::setApplication(<span>$this</span><span>);

 

                   </span><span>//</span><span> set basePath at early as possible to avoid trouble</span>

                   <span>if</span>(<span>is_string</span>(<span>$config</span><span>))

                            </span><span>$config</span>=<span>require</span>(<span>$config</span><span>);

                   </span><span>if</span>(<span>isset</span>(<span>$config</span>['basePath'<span>]))

                   {

                            </span><span>$this</span>->setBasePath(<span>$config</span>['basePath'<span>]);

                            </span><span>unset</span>(<span>$config</span>['basePath'<span>]);

                   }

                   </span><span>else</span>

                            <span>$this</span>->setBasePath('protected'<span>);

                   Yii</span>::setPathOfAlias('application',<span>$this</span>-><span>getBasePath());

                   Yii</span>::setPathOfAlias('webroot',<span>dirname</span>(<span>$_SERVER</span>['SCRIPT_FILENAME'<span>]));

                   </span><span>if</span>(<span>isset</span>(<span>$config</span>['extensionPath'<span>]))

                   {

                            </span><span>$this</span>->setExtensionPath(<span>$config</span>['extensionPath'<span>]);

                            </span><span>unset</span>(<span>$config</span>['extensionPath'<span>]);

                   }

                   </span><span>else</span><span>

                            Yii</span>::setPathOfAlias('ext',<span>$this</span>->getBasePath().DIRECTORY_SEPARATOR.'extensions'<span>);

                   </span><span>if</span>(<span>isset</span>(<span>$config</span>['aliases'<span>]))

                   {

                            </span><span>$this</span>->setAliases(<span>$config</span>['aliases'<span>]);

                            </span><span>unset</span>(<span>$config</span>['aliases'<span>]);

                   }</span></spanmicrosoft>

//The above can be regarded as initialization, setting class references, aliases, paths, etc.

-$ This- & gt; preinit (); // No any use is used for the time being, it is estimated that it is left for the future expansion

                                                                                                                                                                                                                                                                                                 through

                                                                                                                                                                                                                                                                                                  through

                                                                                                                                                                                                                                                                                                Since

                                                                                                                                                                                                                                   Since

                                                                                                                                      

                                                                                                                              

          }

Some methods under $this cannot be found in the current class because they may come from the parent class. The easiest way is to search with ctrl+f. If not, go to the declaration of the class to check:

abstract class CApplication extends CModule

Obviously you need to enter CModule. If you still can’t find the method you want at this time, then continue with the previous process:

abstract class CModule extends CComponent

until class CComponent

It means this is the current home base of these guys. You can also see it from the comments in the code:

CComponent is the base class for all components

It shows that my idea is correct, yes, it is the base class.

Through the code, we can find that in our current application, because many parameters are empty, a lot of logic is skipped directly.

Seeing this, the content of $this is roughly clear. Let’s look back again

return new CWebApplication($config)->run();

Through the previous layer-by-layer analysis, the run method at this time is also easy to find. Just inside CApplication:

<spanmicrosoft yahei font-size:><span>public</span> <span>function</span><span> run()

         {

                   </span><span>if</span>(<span>$this</span>->hasEventHandler('onBeginRequest'<span>)){

                            </span><span>$this</span>->onBeginRequest(<span>new</span> CEvent(<span>$this</span><span>));

                   }

 

                   </span><span>register_shutdown_function</span>(<span>array</span>(<span>$this</span>,'end'),0,<span>false</span><span>);

                   </span><span>$this</span>-><span>processRequest();  

                   </span><span>if</span>(<span>$this</span>->hasEventHandler('onEndRequest'<span>)){

                            </span><span>$this</span>->onEndRequest(<span>new</span> CEvent(<span>$this</span><span>));

                   }

 

         }</span></spanmicrosoft>

 

重点放在:$this->processRequest(); 因为前面和后面部分都是注册事件相关的,当前条件下执行不到。

<spanmicrosoft yahei font-size:><span>abstract</span> <span>public</span> <span>function</span> processRequest(); 这个方法在当前类中是抽象的,所以肯定在它的子类中实现了。回去找CWebApplication:

         <span>public</span> <span>function</span><span> processRequest()

         {

                   </span><span>if</span>(<span>is_array</span>(<span>$this</span>->catchAllRequest) && <span>isset</span>(<span>$this</span>->catchAllRequest[0<span>]))

                   {

                            </span><span>$route</span>=<span>$this</span>->catchAllRequest[0<span>];

                            </span><span>foreach</span>(<span>array_splice</span>(<span>$this</span>->catchAllRequest,1) <span>as</span> <span>$name</span>=><span>$value</span><span>)

                                     </span><span>$_GET</span>[<span>$name</span>]=<span>$value</span><span>;

                   }

                   </span><span>else</span>

                            <span>$route</span>=<span>$this</span>->getUrlManager()->parseUrl(<span>$this</span>-><span>getRequest());

 

                   </span><span>$this</span>->runController(<span>$route</span><span>);

         }</span></spanmicrosoft>

 

 

注意重点在$this->runController($route);

 

<spanmicrosoft yahei font-size:><span>public</span> <span>function</span> runController(<span>$route</span><span>)

         {

                   </span><span>if</span>((<span>$ca</span>=<span>$this</span>->createController(<span>$route</span>))!==<span>null</span><span>)

                   {

                            </span><span>list</span>(<span>$controller</span>,<span>$actionID</span>)=<span>$ca</span><span>;

 

                            </span><span>$oldController</span>=<span>$this</span>-><span>_controller;

                            </span><span>$this</span>->_controller=<span>$controller</span><span>;

                            </span><span>$controller</span>-><span>init();

                            </span><span>$controller</span>->run(<span>$actionID</span><span>);

                            </span><span>$this</span>->_controller=<span>$oldController</span><span>;

                   }

                   </span><span>else</span>

                            <span>throw</span> <span>new</span> CHttpException(404,Yii::t('yii','Unable to resolve the request "{route}".',

                                     <span>array</span>('{route}'=><span>$route</span>===''?<span>$this</span>->defaultController:<span>$route</span><span>)));

         }</span></spanmicrosoft>

 

 

我们要注意的代码只有两行:

$controller->init();

$controller->run($actionID);

这里的$controller可以能过查看createController得知,就是默认的控制器Sitecontroller.php

而Action则是index,你问我是怎么看出来的?哈哈,我在猜不出来的地方echo或var_dump一下不就可以了吗?这么简单的逻辑,还轮不到xdebug 这样的神器出场。

显然,init什么也没有做,看看run做了什么

Sitecontroller中没有run方法,又要去它的父类中查找。

class SiteController extends CController

 

在CController中有这个方法:

<spanmicrosoft yahei font-size:><span>public</span> <span>function</span> run(<span>$actionID</span><span>)

         {

                   </span><span>if</span>((<span>$action</span>=<span>$this</span>->createAction(<span>$actionID</span>))!==<span>null</span><span>)

                   {

                            </span><span>if</span>((<span>$parent</span>=<span>$this</span>->getModule())===<span>null</span><span>){

                                     </span><span>$parent</span>=Yii::<span>app();

                            }

 

                            </span><span>if</span>(<span>$parent</span>->beforeControllerAction(<span>$this</span>,<span>$action</span><span>))

                            {

                                     </span><span>$this</span>->runActionWithFilters(<span>$action</span>,<span>$this</span>-><span>filters());

                                     </span><span>$parent</span>->afterControllerAction(<span>$this</span>,<span>$action</span><span>);

                            }

                   }

                   </span><span>else</span>

                            <span>$this</span>->missingAction(<span>$actionID</span><span>);

         }

 </span></spanmicrosoft>

 

能过查看$this->createAction($actionID),得到return new CInlineAction($this,$actionID);

我们呆会再看这个CInlineAction,先看$this->runActionWithFilters($action,$this->filters());

<spanmicrosoft yahei font-size:><span>public</span> <span>function</span> runActionWithFilters(<span>$action</span>,<span>$filters</span><span>)

         {

                   </span><span>if</span>(<span>empty</span>(<span>$filters</span><span>)){

                            </span><span>$this</span>->runAction(<span>$action</span><span>);

                   }

                   </span><span>else</span><span>

                   {

                            </span><span>$priorAction</span>=<span>$this</span>-><span>_action;

                            </span><span>$this</span>->_action=<span>$action</span><span>;

                            CFilterChain</span>::create(<span>$this</span>,<span>$action</span>,<span>$filters</span>)-><span>run();

                            </span><span>$this</span>->_action=<span>$priorAction</span><span>;

                   }

         }</span></spanmicrosoft>

 

显然$filters是空的,所以执行第一个表达式$this->runAction($action);

 

<spanmicrosoft yahei font-size:><span>public</span> <span>function</span> runAction(<span>$action</span><span>)

         {

 

                   </span><span>$priorAction</span>=<span>$this</span>-><span>_action;

                   </span><span>$this</span>->_action=<span>$action</span><span>;

                   </span><span>if</span>(<span>$this</span>->beforeAction(<span>$action</span><span>))

                   {

 

                            </span><span>if</span>(<span>$action</span>->runWithParams(<span>$this</span>->getActionParams())===<span>false</span><span>){

                                     </span><span>$this</span>->invalidActionParams(<span>$action</span><span>);

                            }

 

                            </span><span>else</span><span>{

                                     </span><span>$this</span>->afterAction(<span>$action</span><span>);

 

                            }

 

                   }

                   </span><span>$this</span>->_action=<span>$priorAction</span><span>;

         }</span></spanmicrosoft>

 

 

这段代码的重点是 $action->runWithParams($this->getActionParams())这一句;

这里的$action就是$this->createAction($actionID)返回的结果,而它的结果就是

return new CInlineAction($this,$actionID);

 

CInlineAction.php

是时候查看CInlineAction了;

 

        

<spanmicrosoft yahei font-size:> <span>public</span> <span>function</span> runWithParams(<span>$params</span><span>)

         {

                   </span><span>$methodName</span>='action'.<span>$this</span>-><span>getId();

                   </span><span>$controller</span>=<span>$this</span>-><span>getController();

                   </span><span>$method</span>=<span>new</span> ReflectionMethod(<span>$controller</span>, <span>$methodName</span><span>);

                   </span><span>if</span>(<span>$method</span>->getNumberOfParameters()>0<span>)

                            </span><span>return</span> <span>$this</span>->runWithParamsInternal(<span>$controller</span>, <span>$method</span>, <span>$params</span><span>);

                   </span><span>else</span>

                            <span>return</span> <span>$controller</span>-><span>$methodName</span><span>();

         }</span></spanmicrosoft>

 

哇哦,好高级,居然还用了反射,不过我喜欢!

不过呢,打印$method发现:

object(ReflectionMethod)#6 (2) {

 

["name"]=>

 

string(11) "actionIndex"

 

["class"]=>

 

string(14) "SiteController"

 

}

没有参数,所以此处代码相当于是执行了SiteController->actionIndex();

在class SiteController extends CController中可以看到actionIndex 的定义

        

<spanmicrosoft yahei font-size:> <span>public</span> <span>function</span><span> actionIndex()

         {

                   </span><span>echo</span> 'Hello World'<span>;

         }</span></spanmicrosoft>

 

于是就看到屏幕上那一句Hello World ,整个程序也就跑完了。也许有人要问了,为什么输出一句话还这么复杂,不是脱了裤子打屁吗? (请允许我的粗俗);

如果是这么简单的需求,当然不可能这么干。举这个例子,只是说明yii的基础流程,为下面的复杂应用做一个过渡。

Yii作为一个优秀的oop框架,这个例子只是介绍了它的继承,接口,mvc中的vc特性,关于数据模型,我将在后面的分析中陆续给出。最终的目标,是利用yii框架简化我们的开发过程。

好了,今天的分析就在到了,如果有什么不妥的,请留言,如果觉得有帮助,请顺手点个推荐!

以上就介绍了YII 的源码分析(-),包括了方面的内容,希望对PHP教程有兴趣的朋友有所帮助。

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn