您好,欢迎访问一九零五行业门户网

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() 一共可以分成三部分
yiicreatewebapplicationrunyii 这个东西是什么?
从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框架简化我们的开发过程。
好了,今天的分析就在到了,如果有什么不妥的,请留言,如果觉得有帮助,请顺手点个推荐!
以上就介绍了yii 的源码分析(-),包括了方面的内容,希望对php教程有兴趣的朋友有所帮助。
其它类似信息

推荐信息