国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計 > 正文

YII 的源碼分析(二)

2019-11-15 01:58:33
字體:
供稿:網(wǎng)友
YII 的

依然是demos目錄,這次我們選擇hangman,一個簡單的猜字游戲

和helloworld應(yīng)用相比,這次多了main.php,打開main看下源碼:

<?phPReturn array(    'name'=>'Hangman Game',    'defaultController'=>'game',    'components'=>array(        'urlManager'=>array(            'urlFormat'=>'path',            'rules'=>array(                'game/guess/<g:/w>'=>'game/guess',            ),        ),    ),);

在我們以后的實際項目中,也是經(jīng)常要用到配置文件的,所以我覺得有必要了解一下yii的配置文件--main.php

'name'=>'這里通常是定義網(wǎng)站的標(biāo)題',也就是我們打開index.php時,在網(wǎng)頁上顯示的標(biāo)題。

'defaultController'=>'這里是默認(rèn)的控制器',也就是我們的index.php后面沒有指定控制器時系統(tǒng)采用的控制器,如果我們這里沒有指出來,默認(rèn)就是site

'components'=>'這里是組件的參數(shù),用多維數(shù)組進(jìn)行配置。' 具體的參數(shù)可以查看yii手冊。

Yii::createWebapplication($config)->run(); 上一次我們已經(jīng)詳細(xì)分析過它了,這里就不再走一遍了。

上次我們沒有配置過程,所以$this->configure($config)什么也沒有做,但是這次有配置參數(shù),所以我們進(jìn)去看看yii做了哪些操作:

CApplication自己沒有實現(xiàn)configure方法,是繼承于CModule.php的:

    public function configure($config)    {        if(is_array($config))        {            foreach($config as $key=>$value)                $this->$key=$value;        }    }

代碼非常簡單,就是把配置參數(shù)的鍵做為類的屬性名,value做為類的屬性值進(jìn)行了擴(kuò)展。

由于url是index.php,后面沒有任何參數(shù),所以都是走的默認(rèn)控制器,也就是我們在main.php中設(shè)定的game. 所以$controller 就等于 controllers/gameController.php, 通過上次的源碼分析我們可以知道,在gameController.php中沒有init方法時,都是走的父類中定義的默認(rèn)方法(實際上是一個空方法),

$controller->run($actionID); == gameController->run(''); 

前面已經(jīng)分析過了,沒有指定時,都是默認(rèn)參數(shù)。那么此時的$actionID為空,actionID就是gameController中定義的默認(rèn)動作:public $defaultAction='play';

runActionWithFilters --->  runAction --> $action->runWithParams

走了這么多過程,和hello world的流程是差不多的。據(jù)上次的分析可以知道,這里執(zhí)行了

$controller->$methodName(); 也就是GameController->actionPlay()到此,我們本節(jié)的重點才真正開始:
    public function actionPlay()    {        static $levels=array(            '10'=>'Easy game; you are allowed 10 misses.',            '5'=>'Medium game; you are allowed 5 misses.',            '3'=>'Hard game; you are allowed 3 misses.',        );        // if a difficulty level is correctly chosen        if(isset($_POST['level']) && isset($levels[$_POST['level']]))        {            $this->Word=$this->generateWord();            $this->guessWord=str_repeat('_',strlen($this->word));            $this->level=$_POST['level'];            $this->misses=0;            $this->setPageState('guessed',null);            // show the guess page            $this->render('guess');        }        else        {            $params=array(                'levels'=>$levels,                // if this is a POST request, it means the level is not chosen                'error'=>Yii::app()->request->isPostRequest,            );            // show the difficulty level page            $this->render('play',$params);        }    }
重點請看 $this->render('play',$params); 這個render方法這么面熟,很多框架中都有類似的方法,比如discuz,smarty,CI 等等. 縱觀yii框架,render 在它整個MVC模式中,是V得以實現(xiàn)的重要骨干。所以有必要把它翻個底朝天。
    public function render($view,$data=null,$return=false)    {        if($this->beforeRender($view))        {            $output=$this->renderPartial($view,$data,true);            if(($layoutFile=$this->getLayoutFile($this->layout))!==false)                $output=$this->renderFile($layoutFile,array('content'=>$output),true);            $this->afterRender($view,$output);            $output=$this->processOutput($output);            if($return)                return $output;            else                echo $output;        }    }

先看$output=$this->renderPartial($view,$data,true); 從字面上來看,就是渲染局部視圖。

    public function renderPartial($view,$data=null,$return=false,$processOutput=false)    {        if(($viewFile=$this->getViewFile($view))!==false)        {      //$viewFile=yii/demos/hangman/protected/views/game/play.php            $output=$this->renderFile($viewFile,$data,true);            if($processOutput)                $output=$this->processOutput($output);            if($return)                return $output;            else                echo $output;        }        else            throw new CException(Yii::t('yii','{controller} cannot find the requested view "{view}".',                array('{controller}'=>get_class($this), '{view}'=>$view)));    }

這里調(diào)用了renderFile來處理,這個renderfile哪里來的,要自己學(xué)會分析繼承關(guān)系,不明白的看第一篇,我這里直接上源碼了:

    public function renderFile($viewFile,$data=null,$return=false)    {        $widgetCount=count($this->_widgetStack);        if(($renderer=Yii::app()->getViewRenderer())!==null && $renderer->fileExtension==='.'.CFileHelper::getExtension($viewFile)){            $content=$renderer->renderFile($this,$viewFile,$data,$return);        }        else{            $content=$this->renderInternal($viewFile,$data,$return);        }        if(count($this->_widgetStack)===$widgetCount){            return $content;        }        else        {            $widget=end($this->_widgetStack);            throw new CException(Yii::t('yii','{controller} contains improperly nested widget tags in its view "{view}". A {widget} widget does not have an endWidget() call.',                array('{controller}'=>get_class($this), '{view}'=>$viewFile, '{widget}'=>get_class($widget))));        }    }

邏輯上走的是renderInternal方法:

    public function renderInternal($_viewFile_,$_data_=null,$_return_=false)    {        // we use special variable names here to avoid conflict when extracting data        if(is_array($_data_)){            extract($_data_,EXTR_PREFIX_SAME,'data');        }        else{            $data=$_data_;        }        if($_return_)        {            ob_start();            ob_implicit_flush(false);            require($_viewFile_);            return ob_get_clean();        }        else            require($_viewFile_);    }

為什么要用ob_start() ?這個方法比較有意思。它非常巧妙的把play.php視圖中的html的內(nèi)容和php輸出的內(nèi)容組裝在了一起。然后整個return 出去,非常值得借鑒的思想。

接著,我們再回到render。走余下的過程。

$output=$this->renderFile($layoutFile,array('content'=>$output),true);
這里直接又調(diào)用了一次renderFile方法,這個$layoutFile是什么呢?就是yii/demos/hangman/protected/views/layouts/main.php通過上次的分析,$output就是main.php的內(nèi)容了,不過呢,是結(jié)合了play.php的內(nèi)容。這又是怎么做到的呢?這就是extract($_data_,EXTR_PREFIX_SAME,'data');所發(fā)揮的功能了。還有一個processOutput方法,輸出前進(jìn)行一些緩存什么的,這里先不深究它。

最后就是echo $output;因此屏幕上就有內(nèi)容顯示出來了。

也就是我們在index.php上最終看到的內(nèi)容了。本次渲染比較簡單,但是該走的邏輯都差不多用到了。

總結(jié)一下:視圖層,是通過render方法進(jìn)行渲染輸出的。而render實際上是分成兩部分來做的,一部分是局部視圖,另一部分是通用視圖。

類似于如下結(jié)構(gòu):

<html><!--這里是通用視圖--><head><title>xxx</title></head><body>                    {{這里是局部視圖內(nèi)容}}</body></html>

render輸出的是兩者融合的內(nèi)容。這樣做的好處也是顯而易見的,避免創(chuàng)建重復(fù)內(nèi)容。


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 慈利县| 栾城县| 西城区| 金寨县| 琼海市| 融水| 广汉市| 洛隆县| 沙河市| 玛曲县| 鄂托克旗| 长岭县| 衡南县| 海林市| 西充县| 九寨沟县| 静乐县| 武夷山市| 望江县| 安丘市| 长汀县| 赤峰市| 永年县| 固原市| 慈利县| 固原市| 泰和县| 葫芦岛市| 祁连县| 婺源县| 安岳县| 蓬莱市| 田阳县| 澜沧| 杭州市| 进贤县| 顺义区| 钦州市| 隆德县| 义乌市| 锡林浩特市|