• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

YII 的源码分析(二)

php 搞代码 3年前 (2022-01-23) 35次浏览 已收录 0个评论

上一篇简单分析了一下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/'=>'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>

我们前面说过,这¥本文来%源[email protected]搞@^&代*@码)网5搞gaodaima代码里只要关注 $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 />这里的$action 需要从CAction -> CInlineAction中去找<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 /></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 />

以上就介绍了YII 的源码分析(二),包括了方面的内容,希望对PHP教程有兴趣的朋友有所帮助。


搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:YII 的源码分析(二)

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址