程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> 關於PHP編程 >> YII 的源碼分析(-),yii源碼分析

YII 的源碼分析(-),yii源碼分析

編輯:關於PHP編程

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發現:

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved