YIIソースコード解析(2)

WBOY
リリース: 2016-06-13 12:11:28
オリジナル
879 人が閲覧しました

YII のソースコード解析 (2)

前回の記事では、yii のアプリケーションの作成から結果を画面に出力するまでのプロセスを簡単に分析しました。今回は、出力に焦点を当てて、もう少し複雑なものを実行します。これは単純な「hello world」行ではなく、ビュー層によって処理する必要があります。

今回は、単純な推測ゲームである Hangman を選択します。古いルールは入り口から始めることです。

index.php:

<?<span style="color: #000000;">php</span><span style="color: #008000;">//</span><span style="color: #008000;"> change the following paths if necessary</span><span style="color: #800080;">$yii</span>=<span style="color: #008080;">dirname</span>(<span style="color: #ff00ff;">__FILE__</span>).'/../../framework/yii.php'<span style="color: #000000;">;</span><span style="color: #800080;">$config</span>=<span style="color: #008080;">dirname</span>(<span style="color: #ff00ff;">__FILE__</span>).'/protected/config/main.php'<span style="color: #000000;">;</span><span style="color: #008000;">//</span><span style="color: #008000;"> remove the following line when in production mode// defined('YII_DEBUG') or define('YII_DEBUG',true);</span><span style="color: #0000ff;">require_once</span>(<span style="color: #800080;">$yii</span><span style="color: #000000;">);Yii</span>::createWebApplication(<span style="color: #800080;">$config</span>)->run();
ログイン後にコピー

helloworld アプリケーションと比較すると、今回は main.php が追加されています。 main を開いてソース コードを確認します。

<?<span style="color: #000000;">php</span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">array</span><span style="color: #000000;">(    </span>'name'=>'Hangman Game',    'defaultController'=>'game',    'components'=><span style="color: #0000ff;">array</span><span style="color: #000000;">(        </span>'urlManager'=><span style="color: #0000ff;">array</span><span style="color: #000000;">(            </span>'urlFormat'=>'path',            'rules'=><span style="color: #0000ff;">array</span><span style="color: #000000;">(                </span>'game/guess/<g:\w>'=>'game/guess',<span style="color: #000000;">            )</span>,<span style="color: #000000;">        )</span>,<span style="color: #000000;">    )</span>,<span style="color: #000000;">);</span>
ログイン後にコピー

今後の実際のプロジェクトでは設定ファイルを使用することが多いので、yii 設定ファイル-main.php

を理解しておく必要があると思います' name'=>'これは通常、Web サイトのタイトルを定義します'。これは、index.php を開いたときに Web ページに表示されるタイトルです。

'defaultController'=>'これはデフォルトのコントローラーです'。これは、index.php の背後にコントローラーが指定されていない場合にシステムによって使用されるコントローラーです。デフォルトはサイト

'components'=>' ここに、多次元配列で構成されたコンポーネントのパラメーターがあります。 '特定のパラメータについては、yii マニュアルを参照してください。

Yii::createWebApplication($config)->run(); 前回詳しく分析しましたが、ここでは簡単に説明します。 .php -> __construct($config) :

<span style="color: #800080;">$this</span>-><span style="color: #000000;">preinit();        </span><span style="color: #800080;">$this</span>-><span style="color: #000000;">initSystemHandlers();        </span><span style="color: #800080;">$this</span>-><span style="color: #000000;">registerCoreComponents();        </span><span style="color: #800080;">$this</span>->configure(<span style="color: #800080;">$config</span><span style="color: #000000;">);        </span><span style="color: #800080;">$this</span>->attachBehaviors(<span style="color: #800080;">$this</span>-><span style="color: #000000;">behaviors);        </span><span style="color: #800080;">$this</span>-><span style="color: #000000;">preloadComponents();        </span><span style="color: #800080;">$this</span>->init();
ログイン後にコピー
前回は設定プロセスがなかったので、$this->configure($config) は何もしませんでしたが、これは設定パラメータがあるときは、Yii がどのような操作を行ったのか見てみましょう:

CApplication 自体はconfigureメソッドを実装していませんが、CModule.phpから継承されています:

    <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> configure(<span style="color: #800080;">$config</span><span style="color: #000000;">)    {        </span><span style="color: #0000ff;">if</span>(<span style="color: #008080;">is_array</span>(<span style="color: #800080;">$config</span><span style="color: #000000;">))        {            </span><span style="color: #0000ff;">foreach</span>(<span style="color: #800080;">$config</span> <span style="color: #0000ff;">as</span> <span style="color: #800080;">$key</span>=><span style="color: #800080;">$value</span><span style="color: #000000;">)                </span><span style="color: #800080;">$this</span>-><span style="color: #800080;">$key</span>=<span style="color: #800080;">$value</span><span style="color: #000000;">;        }    }</span>
ログイン後にコピー
コードは非常に単純です。つまり、構成パラメーターのキーがクラスの属性名として使用され、値がクラスの属性値として使用されます。このプロセスが完了したら、CApplication で run メソッドを実行します。

    <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span><span style="color: #000000;"> run()    {        </span><span style="color: #0000ff;">if</span>(<span style="color: #800080;">$this</span>->hasEventHandler('onBeginRequest'<span style="color: #000000;">))            </span><span style="color: #800080;">$this</span>->onBeginRequest(<span style="color: #0000ff;">new</span> CEvent(<span style="color: #800080;">$this</span><span style="color: #000000;">));        </span><span style="color: #008080;">register_shutdown_function</span>(<span style="color: #0000ff;">array</span>(<span style="color: #800080;">$this</span>,'end'),0,<span style="color: #0000ff;">false</span><span style="color: #000000;">);        </span><span style="color: #800080;">$this</span>-><span style="color: #000000;">processRequest();        </span><span style="color: #0000ff;">if</span>(<span style="color: #800080;">$this</span>->hasEventHandler('onEndRequest'<span style="color: #000000;">))            </span><span style="color: #800080;">$this</span>->onEndRequest(<span style="color: #0000ff;">new</span> CEvent(<span style="color: #800080;">$this</span><span style="color: #000000;">));    }</span>
ログイン後にコピー
前に述べたように、ここでは $this->processRequest(); に注目してください。操作の結果は、 $this->runController(''); を実行することになります。

    <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> runController(<span style="color: #800080;">$route</span><span style="color: #000000;">)    {        </span><span style="color: #0000ff;">if</span>((<span style="color: #800080;">$ca</span>=<span style="color: #800080;">$this</span>->createController(<span style="color: #800080;">$route</span>))!==<span style="color: #0000ff;">null</span><span style="color: #000000;">)        {            </span><span style="color: #0000ff;">list</span>(<span style="color: #800080;">$controller</span>,<span style="color: #800080;">$actionID</span>)=<span style="color: #800080;">$ca</span><span style="color: #000000;">;            </span><span style="color: #800080;">$oldController</span>=<span style="color: #800080;">$this</span>-><span style="color: #000000;">_controller;            </span><span style="color: #800080;">$this</span>->_controller=<span style="color: #800080;">$controller</span><span style="color: #000000;">;            </span><span style="color: #800080;">$controller</span>-><span style="color: #000000;">init();            </span><span style="color: #800080;">$controller</span>->run(<span style="color: #800080;">$actionID</span><span style="color: #000000;">);            </span><span style="color: #800080;">$this</span>->_controller=<span style="color: #800080;">$oldController</span><span style="color: #000000;">;        }        </span><span style="color: #0000ff;">else</span>            <span style="color: #0000ff;">throw</span> <span style="color: #0000ff;">new</span> CHttpException(404,Yii::t('yii','Unable to resolve the request "{route}".',                <span style="color: #0000ff;">array</span>('{route}'=><span style="color: #800080;">$route</span>===''?<span style="color: #800080;">$this</span>->defaultController:<span style="color: #800080;">$route</span><span style="color: #000000;">)));    }</span>
ログイン後にコピー
URL はindex.php であるため、その後ろにパラメータはありません。デフォルトのコントロールは、main.php で設定したゲームであるコントローラーです。したがって、$controller は、controllers/gameController.php と同じになります。gameController に init メソッドがないことがわかります。親クラスで定義されているデフォルトのメソッド (実際には空のメソッド)、

クラス GameController からわかるように、親クラスは CController であり、対応するメソッドを見つけます。 run メソッド:
$controller->run($actionID<span>); == gameController</span>->run(''); gameController上没有实现run方法,于是又是去父类中找run
ログイン後にコピー

<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> run(<span style="color: #800080;">$actionID</span><span style="color: #000000;">)    {        </span><span style="color: #0000ff;">if</span>((<span style="color: #800080;">$action</span>=<span style="color: #800080;">$this</span>->createAction(<span style="color: #800080;">$actionID</span>))!==<span style="color: #0000ff;">null</span><span style="color: #000000;">)        {            </span><span style="color: #0000ff;">if</span>((<span style="color: #800080;">$parent</span>=<span style="color: #800080;">$this</span>->getModule())===<span style="color: #0000ff;">null</span><span style="color: #000000;">)                </span><span style="color: #800080;">$parent</span>=Yii::<span style="color: #000000;">app();            </span><span style="color: #0000ff;">if</span>(<span style="color: #800080;">$parent</span>->beforeControllerAction(<span style="color: #800080;">$this</span>,<span style="color: #800080;">$action</span><span style="color: #000000;">))            {                </span><span style="color: #800080;">$this</span>->runActionWithFilters(<span style="color: #800080;">$action</span>,<span style="color: #800080;">$this</span>-><span style="color: #000000;">filters());                </span><span style="color: #800080;">$parent</span>->afterControllerAction(<span style="color: #800080;">$this</span>,<span style="color: #800080;">$action</span><span style="color: #000000;">);            }        }        </span><span style="color: #0000ff;">else</span>            <span style="color: #800080;">$this</span>->missingAction(<span style="color: #800080;">$actionID</span><span style="color: #000000;">);    }</span>
ログイン後にコピー
指定されていない場合は、デフォルトのパラメーターになります。このときの $actionID は空で、actionID は gameController で定義されたデフォルトのアクションです: public $defaultAction='play'; 非常に多くのプロセスを経た後、このプロセスは hello world と似ています。最後の分析によると、$output= をエコーすると、ここで

runActionWithFilters --->  runAction --> $action->runWithParams<br><br>这里的$action 需要从CAction -> CInlineAction中去找<br><br>
ログイン後にコピー
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> runWithParams(<span style="color: #800080;">$params</span><span style="color: #000000;">)    {        </span><span style="color: #800080;">$methodName</span>='action'.<span style="color: #800080;">$this</span>-><span style="color: #000000;">getId();        </span><span style="color: #800080;">$controller</span>=<span style="color: #800080;">$this</span>-><span style="color: #000000;">getController();        </span><span style="color: #800080;">$method</span>=<span style="color: #0000ff;">new</span> ReflectionMethod(<span style="color: #800080;">$controller</span>, <span style="color: #800080;">$methodName</span><span style="color: #000000;">);        </span><span style="color: #0000ff;">if</span>(<span style="color: #800080;">$method</span>->getNumberOfParameters()>0<span style="color: #000000;">)            </span><span style="color: #0000ff;">return</span> <span style="color: #800080;">$this</span>->runWithParamsInternal(<span style="color: #800080;">$controller</span>, <span style="color: #800080;">$method</span>, <span style="color: #800080;">$params</span><span style="color: #000000;">);        </span><span style="color: #0000ff;">else</span>            <span style="color: #0000ff;">return</span> <span style="color: #800080;">$controller</span>-><span style="color: #800080;">$methodName</span><span style="color: #000000;">();    }</span>
ログイン後にコピー

$controller->$methodName<span>(); 也就是GameController->actionPlay()<br><br>到此,我们本节的重点才真正开始:<br></span>
ログイン後にコピー
が実行されることがわかります。 $this- >renderPartial($view,$data,true); を実行すると、この時点で $output がすでに最終結果を取得していることがわかりました。対応するファイルは views/game/play.php
    <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span><span style="color: #000000;"> actionPlay()    {        </span><span style="color: #0000ff;">static</span> <span style="color: #800080;">$levels</span>=<span style="color: #0000ff;">array</span><span style="color: #000000;">(            </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 style="color: #000000;">        );        </span><span style="color: #008000;">//</span><span style="color: #008000;"> if a difficulty level is correctly chosen</span>        <span style="color: #0000ff;">if</span>(<span style="color: #0000ff;">isset</span>(<span style="color: #800080;">$_POST</span>['level']) && <span style="color: #0000ff;">isset</span>(<span style="color: #800080;">$levels</span>[<span style="color: #800080;">$_POST</span>['level'<span style="color: #000000;">]]))        {            </span><span style="color: #800080;">$this</span>->word=<span style="color: #800080;">$this</span>-><span style="color: #000000;">generateWord();            </span><span style="color: #800080;">$this</span>->guessWord=<span style="color: #008080;">str_repeat</span>('_',<span style="color: #008080;">strlen</span>(<span style="color: #800080;">$this</span>-><span style="color: #000000;">word));            </span><span style="color: #800080;">$this</span>->level=<span style="color: #800080;">$_POST</span>['level'<span style="color: #000000;">];            </span><span style="color: #800080;">$this</span>->misses=0<span style="color: #000000;">;            </span><span style="color: #800080;">$this</span>->setPageState('guessed',<span style="color: #0000ff;">null</span><span style="color: #000000;">);            </span><span style="color: #008000;">//</span><span style="color: #008000;"> show the guess page</span>            <span style="color: #800080;">$this</span>->render('guess'<span style="color: #000000;">);        }        </span><span style="color: #0000ff;">else</span><span style="color: #000000;">        {            </span><span style="color: #800080;">$params</span>=<span style="color: #0000ff;">array</span><span style="color: #000000;">(                </span>'levels'=><span style="color: #800080;">$levels</span>,                <span style="color: #008000;">//</span><span style="color: #008000;"> if this is a POST request, it means the level is not chosen</span>                'error'=>Yii::app()->request->isPostRequest,<span style="color: #000000;">            );            </span><span style="color: #008000;">//</span><span style="color: #008000;"> show the difficulty level page</span>            <span style="color: #800080;">$this</span>->render('play',<span style="color: #800080;">$params</span><span style="color: #000000;">);        }    }</span>
ログイン後にコピー
で、最終的にはindex.php で確認できます。このレンダリングは比較的単純なため、プログラムの処理は少ないですが、ソースコードを見るとわかるように、テーマなど多くの処理が行われています。今回はまずこれを分析してみます。おやすみ!
<span>显然走的是else的逻辑,重点请看</span> $this->render('play',$params); 这个render方法这么面熟,很多框架中都有类似的方法,比如discuz,smarty,CI 等等. 纵观yii框架,rnder 在它整个MVC模式中,是V得以实现的重要骨干。所以有必要把它翻个底朝天。<br>在CController.php中有这个方法:
ログイン後にコピー
    <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> render(<span style="color: #800080;">$view</span>,<span style="color: #800080;">$data</span>=<span style="color: #0000ff;">null</span>,<span style="color: #800080;">$return</span>=<span style="color: #0000ff;">false</span><span style="color: #000000;">)    {        </span><span style="color: #0000ff;">if</span>(<span style="color: #800080;">$this</span>->beforeRender(<span style="color: #800080;">$view</span><span style="color: #000000;">))        {            </span><span style="color: #800080;">$output</span>=<span style="color: #800080;">$this</span>->renderPartial(<span style="color: #800080;">$view</span>,<span style="color: #800080;">$data</span>,<span style="color: #0000ff;">true</span><span style="color: #000000;">);            </span><span style="color: #0000ff;">if</span>((<span style="color: #800080;">$layoutFile</span>=<span style="color: #800080;">$this</span>->getLayoutFile(<span style="color: #800080;">$this</span>->layout))!==<span style="color: #0000ff;">false</span><span style="color: #000000;">)                </span><span style="color: #800080;">$output</span>=<span style="color: #800080;">$this</span>->renderFile(<span style="color: #800080;">$layoutFile</span>,<span style="color: #0000ff;">array</span>('content'=><span style="color: #800080;">$output</span>),<span style="color: #0000ff;">true</span><span style="color: #000000;">);            </span><span style="color: #800080;">$this</span>->afterRender(<span style="color: #800080;">$view</span>,<span style="color: #800080;">$output</span><span style="color: #000000;">);            </span><span style="color: #800080;">$output</span>=<span style="color: #800080;">$this</span>->processOutput(<span style="color: #800080;">$output</span><span style="color: #000000;">);            </span><span style="color: #0000ff;">if</span>(<span style="color: #800080;">$return</span><span style="color: #000000;">)                </span><span style="color: #0000ff;">return</span> <span style="color: #800080;">$output</span><span style="color: #000000;">;            </span><span style="color: #0000ff;">else</span>                <span style="color: #0000ff;">echo</span> <span style="color: #800080;">$output</span><span style="color: #000000;">;        }    }</span>
ログイン後にコピー
関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート