搜索
首页后端开发php教程YII 的源码分析(-)

做为源码分析的首秀,我就挑了yii(读作歪依依而不是歪爱爱);它的赞美之词我就不多说了,直接入正题。先准备材料,建议直从官网下载yii的源码包(1.1.15)最新版本。

在demos里边有一个最简单的应用—helloworld.就是用yii框架输出一句话:”hello world”;

我就从它下手,分析框架执行一个最小流程要经过哪些组件,浅析它的运行过程。

首先从单一入口文件开始阅读。(源码一般都是从调用处开始分析)

Index.php->

// include Yii bootstrap file

//引入启动文件

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

 

yii.php ->

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

//YiiBase是一个助手类,它服务于整个框架。 这里定义了许多重要的常量

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

//注册自动加载类

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

//导入接口类

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

//启动应用

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

代码到这里似乎就终结了,页面的内容也程现出来,可是框架到底做了些什么,我们却一无所知。所以我们需要把这一步进行分解,把里边的细节暴露出来。

Yii::createWebApplication()->run() 一共可以分成三部分

  1. Yii
  2. createWebApplication
  3. run

Yii 这个东西是什么?

从yii.php 可以找到这样一行代码class Yii extends YiiBase

说明它就是YiiBase的继承类,而且作者的扩展是留空的,所以Yii就是YiiBase的一个引用而已。所以createWebApplication这个静态方法也得去YiiBase中查找了。

在YiiBase.php中,很容易就发现了这个方法:

public static function createWebApplication($config=null)

         {

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

         }

它又把任务传递给了createApplication:

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

         {

                   return new $class($config);

         }

结合起来看,createWebApplication () 就是return new CWebApplication($config);

这个CWebApplication类又在哪呢?它又是怎么引入的呢?

带着一系列的问题,我又回到了YiiBase.php

那里边定义了一个很长的数组,你可以找到:

'CWebApplication' => '/web/CWebApplication.php',这就是自动加载类中的一员

关于它是如何实现自动加载的,可以查看spl_autoload_register的相关文档,此处就节外生枝了.

 

我们继续往CWebApplication这个里边深挖。打开/web/CWebApplication.php这个文件。

前面提到return new CWebApplication($config);根据我的经验,用了new ,通常会有一个构造函数的,但我却没有找到它的构造函数,肯定是在它的父类中,于是我往上找,class CWebApplication extends CApplication 果然被我发现了,这就跟挖泥鳅一样的,得顺着线索一点点的找,要有耐心。

 

CApplication 中果然有构造函数,代码如下:

<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>

 

   //以上都可以看成是初始化,设置类的引用,别名,路径什么的。

                   $this->preinit();//暂时未发现有什么用,估计是留给后面扩展用的

 

                   $this->initSystemHandlers();//设置错误处理

                   $this->registerCoreComponents();//注册核心组件

 

                   $this->configure($config);        //通过配置文件扩展类的属性,为空的时候什么也不做

                   $this->attachBehaviors($this->behaviors);

                   $this->preloadComponents();

 

                   $this->init();

         }

$this下面的某些方法,在当前类是找不到的,因为它们可能是来自父类,最简单的方法就是ctrl+f搜索一下,没有就去类的声明处查看:

abstract class CApplication extends CModule  

显然要进入CModule,如果此时还找不到想要方法,那么继续上一过程:

abstract class CModule extends CComponent

直到class CComponent

说明这就是当前这些家伙的老巢了。从代码的中注释中也可以看到:

CComponent is the base class for all components

说明我的想法是正确的,没错,它就是基类。

透过代码,我们可以发现,我们当前的应用,因为很多参数是空,所以很多逻辑都是直接跳过的。

看到这,$this的内容也大致明了啦。我们再回头看看

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

通过前面的层层分析,此时的run方法也很好找了。就在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教程有兴趣的朋友有所帮助。

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
继续使用PHP:耐力的原因继续使用PHP:耐力的原因Apr 19, 2025 am 12:23 AM

PHP仍然流行的原因是其易用性、灵活性和强大的生态系统。1)易用性和简单语法使其成为初学者的首选。2)与web开发紧密结合,处理HTTP请求和数据库交互出色。3)庞大的生态系统提供了丰富的工具和库。4)活跃的社区和开源性质使其适应新需求和技术趋势。

PHP和Python:探索他们的相似性和差异PHP和Python:探索他们的相似性和差异Apr 19, 2025 am 12:21 AM

PHP和Python都是高层次的编程语言,广泛应用于Web开发、数据处理和自动化任务。1.PHP常用于构建动态网站和内容管理系统,而Python常用于构建Web框架和数据科学。2.PHP使用echo输出内容,Python使用print。3.两者都支持面向对象编程,但语法和关键字不同。4.PHP支持弱类型转换,Python则更严格。5.PHP性能优化包括使用OPcache和异步编程,Python则使用cProfile和异步编程。

PHP和Python:解释了不同的范例PHP和Python:解释了不同的范例Apr 18, 2025 am 12:26 AM

PHP主要是过程式编程,但也支持面向对象编程(OOP);Python支持多种范式,包括OOP、函数式和过程式编程。PHP适合web开发,Python适用于多种应用,如数据分析和机器学习。

PHP和Python:深入了解他们的历史PHP和Python:深入了解他们的历史Apr 18, 2025 am 12:25 AM

PHP起源于1994年,由RasmusLerdorf开发,最初用于跟踪网站访问者,逐渐演变为服务器端脚本语言,广泛应用于网页开发。Python由GuidovanRossum于1980年代末开发,1991年首次发布,强调代码可读性和简洁性,适用于科学计算、数据分析等领域。

在PHP和Python之间进行选择:指南在PHP和Python之间进行选择:指南Apr 18, 2025 am 12:24 AM

PHP适合网页开发和快速原型开发,Python适用于数据科学和机器学习。1.PHP用于动态网页开发,语法简单,适合快速开发。2.Python语法简洁,适用于多领域,库生态系统强大。

PHP和框架:现代化语言PHP和框架:现代化语言Apr 18, 2025 am 12:14 AM

PHP在现代化进程中仍然重要,因为它支持大量网站和应用,并通过框架适应开发需求。1.PHP7提升了性能并引入了新功能。2.现代框架如Laravel、Symfony和CodeIgniter简化开发,提高代码质量。3.性能优化和最佳实践进一步提升应用效率。

PHP的影响:网络开发及以后PHP的影响:网络开发及以后Apr 18, 2025 am 12:10 AM

PHPhassignificantlyimpactedwebdevelopmentandextendsbeyondit.1)ItpowersmajorplatformslikeWordPressandexcelsindatabaseinteractions.2)PHP'sadaptabilityallowsittoscaleforlargeapplicationsusingframeworkslikeLaravel.3)Beyondweb,PHPisusedincommand-linescrip

PHP类型提示如何起作用,包括标量类型,返回类型,联合类型和无效类型?PHP类型提示如何起作用,包括标量类型,返回类型,联合类型和无效类型?Apr 17, 2025 am 12:25 AM

PHP类型提示提升代码质量和可读性。1)标量类型提示:自PHP7.0起,允许在函数参数中指定基本数据类型,如int、float等。2)返回类型提示:确保函数返回值类型的一致性。3)联合类型提示:自PHP8.0起,允许在函数参数或返回值中指定多个类型。4)可空类型提示:允许包含null值,处理可能返回空值的函数。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热工具

MinGW - 适用于 Windows 的极简 GNU

MinGW - 适用于 Windows 的极简 GNU

这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

EditPlus 中文破解版

EditPlus 中文破解版

体积小,语法高亮,不支持代码提示功能

Atom编辑器mac版下载

Atom编辑器mac版下载

最流行的的开源编辑器

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境