搜尋
首頁php教程php手册YII 的源码分析(二),yii源码分析

YII 的源码分析(二),yii源码分析

上一篇简单分析了一下yii的流程,从创建一个应用,到屏幕上输出结果。这一次我来一个稍复杂一点的,重点在输出上,不再是简单的一行"hello world",而是要经过view(视图)层的处理。

依然是demos目录,这次我们选择hangman,一个简单的猜字游戏。老规则,还是从入口处开始看。

index.php:

<?<span>php

</span><span>//</span><span> change the following paths if necessary</span>
<span>$yii</span>=<span>dirname</span>(<span>__FILE__</span>).'/../../framework/yii.php'<span>;
</span><span>$config</span>=<span>dirname</span>(<span>__FILE__</span>).'/protected/config/main.php'<span>;

</span><span>//</span><span> remove the following line when in production mode
// defined('YII_DEBUG') or define('YII_DEBUG',true);</span>

<span>require_once</span>(<span>$yii</span><span>);
Yii</span>::createWebApplication(<span>$config</span>)->run();

和helloworld应用相比,这次多了main.php,打开main看下源码:

<?<span>php

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

在我们以后的实际项目中,也是经常要用到配置文件的,所以我觉得有必要了解一下yii的配置文件--main.php

'name'=>'这里通常是定义网站的标题',也就是我们打开index.php时,在网页上显示的标题。

'defaultController'=>'这里是默认的控制器',也就是我们的index.php后面没有指定控制器时系统采用的控制器,如果我们这里没有指出来,默认就是site

'components'=>'这里是组件的参数,用多维数组进行配置。' 具体的参数可以查看yii手册。

Yii::createWebApplication($config)->run(); 上一次我们已经详细分析过它了,这里再简单的走一遍:

CWebApplication.php -> CApplication.php -> __construct($config) :

<span>$this</span>-><span>preinit();

        </span><span>$this</span>-><span>initSystemHandlers();
        </span><span>$this</span>-><span>registerCoreComponents();

        </span><span>$this</span>->configure(<span>$config</span><span>);
        </span><span>$this</span>->attachBehaviors(<span>$this</span>-><span>behaviors);
        </span><span>$this</span>-><span>preloadComponents();

        </span><span>$this</span>->init();

上次我们没有配置过程,所以$this->configure($config)什么也没有做,但是这次有配置参数,所以我们进去看看yii做了哪些操作:

CApplication自己没有实现configure方法,是继承于CModule.php的:

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

代码非常简单,就是把配置参数的键做为类的属性名,value做为类的属性值进行了扩展。完成这一过程就运行CApplication 上的run方法了。

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

我们前面说过,这里只要关注 $this->processRequest(); 就可以了。运行的结果就是执行$this->runController('');  

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

由于url是index.php,后面没有任何参数,所以都是走的默认控制器,也就是我们在main.php中设定的game. 所以$controller 就等于 controllers/gameController.php, 通过上次的源码分析我们可以知道,在gameController.php中没有init方法时,都是走的父类中定义的默认方法(实际上是一个空方法),

$controller->run($actionID<span>); == gameController</span>->run(''); gameController上没有实现run方法,于是又是去父类中找run

从class GameController extends CController 可以看出,父类是CController , 找到相应的run方法:

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

前面已经分析过了,没有指定时,都是默认参数。那么此时的$actionID为空,actionID就是gameController中定义的默认动作:public $defaultAction='play'; 

runActionWithFilters --->  runAction --> $action->runWithParams<br /><br />这里的$action 需要从CAction -> CInlineAction中去找<br /><br />
<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>

走了这么多过程,和hello world的流程是差不多的。据上次的分析可以知道,这里执行了

$controller->$methodName<span>(); 也就是GameController->actionPlay()<br /><br />到此,我们本节的重点才真正开始:<br /></span>
    <span>public</span> <span>function</span><span> actionPlay()
    {
        </span><span>static</span> <span>$levels</span>=<span>array</span><span>(
            </span>'10'=>'Easy game; you are allowed 10 misses.',
            '5'=>'Medium game; you are allowed 5 misses.',
            '3'=>'Hard game; you are allowed 3 misses.',<span>
        );

        </span><span>//</span><span> if a difficulty level is correctly chosen</span>
        <span>if</span>(<span>isset</span>(<span>$_POST</span>['level']) && <span>isset</span>(<span>$levels</span>[<span>$_POST</span>['level'<span>]]))
        {
            </span><span>$this</span>->word=<span>$this</span>-><span>generateWord();
            </span><span>$this</span>->guessWord=<span>str_repeat</span>('_',<span>strlen</span>(<span>$this</span>-><span>word));
            </span><span>$this</span>->level=<span>$_POST</span>['level'<span>];
            </span><span>$this</span>->misses=0<span>;
            </span><span>$this</span>->setPageState('guessed',<span>null</span><span>);
            </span><span>//</span><span> show the guess page</span>
            <span>$this</span>->render('guess'<span>);
        }
        </span><span>else</span><span>
        {
            </span><span>$params</span>=<span>array</span><span>(
                </span>'levels'=><span>$levels</span>,
                <span>//</span><span> if this is a POST request, it means the level is not chosen</span>
                'error'=>Yii::app()->request->isPostRequest,<span>
            );
            </span><span>//</span><span> show the difficulty level page</span>
            <span>$this</span>->render('play',<span>$params</span><span>);
        }
    }</span>
<span>显然走的是else的逻辑,重点请看</span> $this->render('play',$params); 这个render方法这么面熟,很多框架中都有类似的方法,比如discuz,smarty,CI 等等. 纵观yii框架,rnder 在它整个MVC模式中,是V得以实现的重要骨干。所以有必要把它翻个底朝天。<br />在CController.php中有这个方法:
    <span>public</span> <span>function</span> render(<span>$view</span>,<span>$data</span>=<span>null</span>,<span>$return</span>=<span>false</span><span>)
    {
        </span><span>if</span>(<span>$this</span>->beforeRender(<span>$view</span><span>))
        {
            </span><span>$output</span>=<span>$this</span>->renderPartial(<span>$view</span>,<span>$data</span>,<span>true</span><span>);
            </span><span>if</span>((<span>$layoutFile</span>=<span>$this</span>->getLayoutFile(<span>$this</span>->layout))!==<span>false</span><span>)
                </span><span>$output</span>=<span>$this</span>->renderFile(<span>$layoutFile</span>,<span>array</span>('content'=><span>$output</span>),<span>true</span><span>);

            </span><span>$this</span>->afterRender(<span>$view</span>,<span>$output</span><span>);

            </span><span>$output</span>=<span>$this</span>->processOutput(<span>$output</span><span>);

            </span><span>if</span>(<span>$return</span><span>)
                </span><span>return</span> <span>$output</span><span>;
            </span><span>else</span>
                <span>echo</span> <span>$output</span><span>;
        }
    }</span>

当我们echo $output=$this->renderPartial($view,$data,true);的时候,就发现,此时的$output已经就拿到我们最终的结果了。它对应的文件是views/game/play.php

也就是我们在index.php上最终看到的内容了。由于本次渲染比较简单,所以程序经过的流程也较少,但是从源码中可以看到,里边进行了许多的处理,比如主题什么的。本次就先分析到这。晚安!

<br /><br /><br />
陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

WebStorm Mac版

WebStorm Mac版

好用的JavaScript開發工具

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

將Eclipse與SAP NetWeaver應用伺服器整合。

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。