欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  后端开发

YII 的源码分析(-),yii源码分析_PHP教程

程序员文章站 2022-05-10 14:25:38
...

YII 的源码分析(-),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() 一共可以分成三部分

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 中果然有构造函数,代码如下:

public function __construct($config=null)

         {

                   Yii::setApplication($this);

 

                   // set basePath at early as possible to avoid trouble

                   if(is_string($config))

                            $config=require($config);

                   if(isset($config['basePath']))

                   {

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

                            unset($config['basePath']);

                   }

                   else

                            $this->setBasePath('protected');

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

                   Yii::setPathOfAlias('webroot',dirname($_SERVER['SCRIPT_FILENAME']));

                   if(isset($config['extensionPath']))

                   {

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

                            unset($config['extensionPath']);

                   }

                   else

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

                   if(isset($config['aliases']))

                   {

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

                            unset($config['aliases']);

                   }

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

$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 里边:

public function run()

         {

                   if($this->hasEventHandler('onBeginRequest')){

                            $this->onBeginRequest(new CEvent($this));

                   }

 

                   register_shutdown_function(array($this,'end'),0,false);

                   $this->processRequest();  

                   if($this->hasEventHandler('onEndRequest')){

                            $this->onEndRequest(new CEvent($this));

                   }

 

         }

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

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

         public function processRequest()

         {

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

                   {

                            $route=$this->catchAllRequest[0];

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

                                     $_GET[$name]=$value;

                   }

                   else

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

 

                   $this->runController($route);

         }

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

public function runController($route)

         {

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

                   {

                            list($controller,$actionID)=$ca;

 

                            $oldController=$this->_controller;

                            $this->_controller=$controller;

                            $controller->init();

                            $controller->run($actionID);

                            $this->_controller=$oldController;

                   }

                   else

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

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

         }

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

$controller->init();

$controller->run($actionID);

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

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

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

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

class SiteController extends CController

在CController中有这个方法:

public function run($actionID)

         {

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

                   {

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

                                     $parent=Yii::app();

                            }

 

                            if($parent->beforeControllerAction($this,$action))

                            {

                                     $this->runActionWithFilters($action,$this->filters());

                                     $parent->afterControllerAction($this,$action);

                            }

                   }

                   else

                            $this->missingAction($actionID);

         }

 

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

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

public function runActionWithFilters($action,$filters)

         {

                   if(empty($filters)){

                            $this->runAction($action);

                   }

                   else

                   {

                            $priorAction=$this->_action;

                            $this->_action=$action;

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

                            $this->_action=$priorAction;

                   }

         }

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

public function runAction($action)

         {

 

                   $priorAction=$this->_action;

                   $this->_action=$action;

                   if($this->beforeAction($action))

                   {

 

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

                                     $this->invalidActionParams($action);

                            }

 

                            else{

                                     $this->afterAction($action);

 

                            }

 

                   }

                   $this->_action=$priorAction;

         }

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

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

return new CInlineAction($this,$actionID);

CInlineAction.php

是时候查看CInlineAction了;

 public function runWithParams($params)

         {

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

                   $controller=$this->getController();

                   $method=new ReflectionMethod($controller, $methodName);

                   if($method->getNumberOfParameters()>0)

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

                   else

                            return $controller->$methodName();

         }

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

不过呢,打印$method发现:

object(ReflectionMethod)#6 (2) {

["name"]=>

string(11) "actionIndex"

["class"]=>

string(14) "SiteController"

}

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

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

 public function actionIndex()

         {

                   echo 'Hello World';

         }

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

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

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

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

www.bkjia.comtruehttp://www.bkjia.com/PHPjc/924356.htmlTechArticleYII 的源码分析(-),yii源码分析 做为源码分析的首秀,我就挑了yii(读作歪依依而不是歪爱爱);它的赞美之词我就不多说了,直接入正题。先...
相关标签: yii