zoukankan      html  css  js  c++  java
  • YII 的源码分析(三)

    前面已经看完了启动一个yii程序所要经过的流程,以及渲染一个页面是怎么完成的。今天要分析的是yii是如何处理用户请求的。也就是控制和动作部分。

    还是以helloworld为例演示这一过程。我们在地址栏输入http://localhost/study/yii/demos/helloworld/index.php,页面就显示了hello world.

    前面的分析都是用的默认值,但是如果url有参数的时候,yii又是怎么处理的呢?带着这个问题,我们具体来分析一下。

    在CWebApplication中有这样一行代码:

    $route=$this->getUrlManager()->parseUrl($this->getRequest());

    这就是传说中的路由了,是不是有点小鸡冻呢?先看看getUrlManager是个神马。

        public function getUrlManager()
        {
            return $this->getComponent('urlManager');
        }

    这个又要通过找关系了.

        public function getComponent($id,$createIfNull=true)
        {
            if(isset($this->_components[$id]))
                return $this->_components[$id];
            elseif(isset($this->_componentConfig[$id]) && $createIfNull)
            {
                $config=$this->_componentConfig[$id];
                if(!isset($config['enabled']) || $config['enabled'])
                {
                    Yii::trace("Loading "$id" application component",'system.CModule');
                    unset($config['enabled']);
                    $component=Yii::createComponent($config);
                    $component->init();
                    return $this->_components[$id]=$component;
                }
            }
        }

    执行了return $this->_components[$id]; id就是传进去的urlManager,其实从这里也还看不出什么,直接找到urlManager这个类,看parseUrl:

        public function parseUrl($request)
        {
            if($this->getUrlFormat()===self::PATH_FORMAT)
            {
                $rawPathInfo=$request->getPathInfo();
                $pathInfo=$this->removeUrlSuffix($rawPathInfo,$this->urlSuffix);
                foreach($this->_rules as $i=>$rule)
                {
                    if(is_array($rule))
                        $this->_rules[$i]=$rule=Yii::createComponent($rule);
                    if(($r=$rule->parseUrl($this,$request,$pathInfo,$rawPathInfo))!==false)
                        return isset($_GET[$this->routeVar]) ? $_GET[$this->routeVar] : $r;
                }
                if($this->useStrictParsing)
                    throw new CHttpException(404,Yii::t('yii','Unable to resolve the request "{route}".',
                        array('{route}'=>$pathInfo)));
                else
                    return $pathInfo;
            }
            elseif(isset($_GET[$this->routeVar]))
                return $_GET[$this->routeVar];
            elseif(isset($_POST[$this->routeVar]))
                return $_POST[$this->routeVar];
            else
                return '';
        }

    从上面的代码来看,如果我们不在url上传点东西,直接就return ''了。于是问题来了,参数要怎么传呢?

    isset($_GET[$this->routeVar]) 

    public $routeVar='r';

    于是有办法了,让我们一起来使点坏吧。加上这样的一个参数helloworld/index.php?r=abc

    发现报错了。说明abc这个控制器是不存在的,事实上也是不存在的,使点小坏坏而已,正所谓男人不坏,女人不爱。

    改成helloworld/index.php?r=site就可以显示hello world了,这是什么鬼原理呢?原因很简单,因为定义了site控制器嘛。

    class SiteController extends CController
    {
        /**
         * Index action is the default action in a controller.
         */
        public function actionIndex()
        {
            echo 'Hello World';
        }
    }

    好吧,这个我没有意见,但是actionIndex又是神么鬼?在yii中,这称为动作。它捕获的是控制器后面的参数,如果我们输?r=site/index就是index,动作是用“/"进行分隔的,为了验正一下我说的不是骗女孩子的鬼话,我在site控制器里加一个动作给你看一下:

    class SiteController extends CController
    {
        /**
         * Index action is the default action in a controller.
         */
        public function actionIndex()
        {
            echo 'Hello World';
        }
    
        public function actionView()
        {
            echo 'Hello View';
        }
    
    }

    访问?r=site/view的时候,是不是看到输出'Hello View'了呢?肯定是的,虽然我读的书少,但是你骗不了我的,有图有真相:

    我一点儿也不喜欢用site这个名字,test才是我的最爱,于是我又建了一个test控制器来尝试一下。

    眼尖的一定看到怎么写了一个actions,这是什么鬼?我也是刚试了才知道,它其实是另一种表示方式。

    我记得在blog那个例子中有用过,用来显示验证码:

        /**
         * Declares class-based actions.
         */
        public function actions()
        {
            return array(
                // captcha action renders the CAPTCHA image displayed on the contact page
                'captcha'=>array(
                    'class'=>'CCaptchaAction',
                    'backColor'=>0xFFFFFF,
                ),
                // page action renders "static" pages stored under 'protected/views/site/pages'
                // They can be accessed via: index.php?r=site/page&view=FileName
                'page'=>array(
                    'class'=>'CViewAction',
                ),
            );
        }

    我把它理解为集中声明第三方业务的动作集合,因为本控制器内的动作,我觉得还是action+ID 的方式直接。

    什么鬼?你说我用的是index.php/site/captcha 而不是index.php?r=site/captcha .这又得从配置文件说起。

            'urlManager'=>array(
                'urlFormat'=>'path',
                'rules'=>array(
                    'post/<id:d+>/<title:.*?>'=>'post/view',
                    'posts/<tag:.*?>'=>'post/index',
                    '<controller:w+>/<action:w+>'=>'<controller>/<action>',
                ),
            ),

    urlFormat 有path 和 get两种,如果在main.php中没有指定,那么就是get方式,也就是index.php?r=site/captcha这种。如果指定了,即index.php/site/captcha这种

    从字面上也很好理解,path就是像路径的格式,get就是?这种形式。

    关于路由和控制器部分的内容还有很多,但是本节就到这里了。

  • 相关阅读:
    python
    突然萌发关于 redis 的想法(1)
    Liunx
    Git
    说一下数据库查询 和 分页问题的解决
    易忘点
    python
    python
    python
    python
  • 原文地址:https://www.cnblogs.com/afrog/p/4177824.html
Copyright © 2011-2022 走看看