0

0

YII 的源码分析(3)

php中文网

php中文网

发布时间:2016-06-13 12:12:09

|

1022人浏览过

|

来源于php中文网

原创

YII 的源码分析(三)

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

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

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

在CWebApplication中有这样一行代码:

<span style="color: #800080;">$route</span>=<span style="color: #800080;">$this</span>->getUrlManager()->parseUrl(<span style="color: #800080;">$this</span>->getRequest());

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

    <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span><span style="color: #000000;"> getUrlManager()    {        </span><span style="color: #0000ff;">return</span> <span style="color: #800080;">$this</span>->getComponent('urlManager'<span style="color: #000000;">);    }</span>

这个又要通过找关系了.

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

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

    <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> parseUrl(<span style="color: #800080;">$request</span><span style="color: #000000;">)    {        </span><span style="color: #0000ff;">if</span>(<span style="color: #800080;">$this</span>->getUrlFormat()===self::<span style="color: #000000;">PATH_FORMAT)        {            </span><span style="color: #800080;">$rawPathInfo</span>=<span style="color: #800080;">$request</span>-><span style="color: #000000;">getPathInfo();            </span><span style="color: #800080;">$pathInfo</span>=<span style="color: #800080;">$this</span>->removeUrlSuffix(<span style="color: #800080;">$rawPathInfo</span>,<span style="color: #800080;">$this</span>-><span style="color: #000000;">urlSuffix);            </span><span style="color: #0000ff;">foreach</span>(<span style="color: #800080;">$this</span>->_rules <span style="color: #0000ff;">as</span> <span style="color: #800080;">$i</span>=><span style="color: #800080;">$rule</span><span style="color: #000000;">)            {                </span><span style="color: #0000ff;">if</span>(<span style="color: #008080;">is_array</span>(<span style="color: #800080;">$rule</span><span style="color: #000000;">))                    </span><span style="color: #800080;">$this</span>->_rules[<span style="color: #800080;">$i</span>]=<span style="color: #800080;">$rule</span>=Yii::createComponent(<span style="color: #800080;">$rule</span><span style="color: #000000;">);                </span><span style="color: #0000ff;">if</span>((<span style="color: #800080;">$r</span>=<span style="color: #800080;">$rule</span>->parseUrl(<span style="color: #800080;">$this</span>,<span style="color: #800080;">$request</span>,<span style="color: #800080;">$pathInfo</span>,<span style="color: #800080;">$rawPathInfo</span>))!==<span style="color: #0000ff;">false</span><span style="color: #000000;">)                    </span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">isset</span>(<span style="color: #800080;">$_GET</span>[<span style="color: #800080;">$this</span>->routeVar]) ? <span style="color: #800080;">$_GET</span>[<span style="color: #800080;">$this</span>->routeVar] : <span style="color: #800080;">$r</span><span style="color: #000000;">;            }            </span><span style="color: #0000ff;">if</span>(<span style="color: #800080;">$this</span>-><span style="color: #000000;">useStrictParsing)                </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;">$pathInfo</span><span style="color: #000000;">)));            </span><span style="color: #0000ff;">else</span>                <span style="color: #0000ff;">return</span> <span style="color: #800080;">$pathInfo</span><span style="color: #000000;">;        }        </span><span style="color: #0000ff;">elseif</span>(<span style="color: #0000ff;">isset</span>(<span style="color: #800080;">$_GET</span>[<span style="color: #800080;">$this</span>-><span style="color: #000000;">routeVar]))            </span><span style="color: #0000ff;">return</span> <span style="color: #800080;">$_GET</span>[<span style="color: #800080;">$this</span>-><span style="color: #000000;">routeVar];        </span><span style="color: #0000ff;">elseif</span>(<span style="color: #0000ff;">isset</span>(<span style="color: #800080;">$_POST</span>[<span style="color: #800080;">$this</span>-><span style="color: #000000;">routeVar]))            </span><span style="color: #0000ff;">return</span> <span style="color: #800080;">$_POST</span>[<span style="color: #800080;">$this</span>-><span style="color: #000000;">routeVar];        </span><span style="color: #0000ff;">else</span>            <span style="color: #0000ff;">return</span> ''<span style="color: #000000;">;    }</span>

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

isset($_GET[$this-><span>routeVar]) <br><br></span>
<span style="color: #0000ff;">public</span> <span style="color: #800080;">$routeVar</span>='r';

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

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

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

<span style="color: #0000ff;">class</span> SiteController <span style="color: #0000ff;">extends</span><span style="color: #000000;"> CController{    </span><span style="color: #008000;">/*</span><span style="color: #008000;">*     * Index action is the default action in a controller.     </span><span style="color: #008000;">*/</span>    <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span><span style="color: #000000;"> actionIndex()    {        </span><span style="color: #0000ff;">echo</span> 'Hello World'<span style="color: #000000;">;    }</span><span style="color: #000000;">}</span>

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

<span style="color: #0000ff;">class</span> SiteController <span style="color: #0000ff;">extends</span><span style="color: #000000;"> CController{    </span><span style="color: #008000;">/*</span><span style="color: #008000;">*     * Index action is the default action in a controller.     </span><span style="color: #008000;">*/</span>    <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span><span style="color: #000000;"> actionIndex()    {        </span><span style="color: #0000ff;">echo</span> 'Hello World'<span style="color: #000000;">;    }    </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span><span style="color: #000000;"> actionView()    {        </span><span style="color: #0000ff;">echo</span> 'Hello View'<span style="color: #000000;">;    }}</span>

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

Codiga
Codiga

可自定义的静态代码分析检测工具

下载

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

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

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

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

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

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

        '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>'post/<id:\d+>/<title:.*?>'=>'post/view',                'posts/<tag:.*?>'=>'post/index',                '<controller:\w+>/<action:\w+>'=>'<controller>/<action>',<span style="color: #000000;">            )</span>,<span style="color: #000000;">        )</span>,

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

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

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

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法
pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法

本专题系统整理pixiv网页版官网入口及登录访问方式,涵盖官网登录页面直达路径、在线阅读入口及快速进入方法说明,帮助用户高效找到pixiv官方网站,实现便捷、安全的网页端浏览与账号登录体验。

616

2026.02.13

微博网页版主页入口与登录指南_官方网页端快速访问方法
微博网页版主页入口与登录指南_官方网页端快速访问方法

本专题系统整理微博网页版官方入口及网页端登录方式,涵盖首页直达地址、账号登录流程与常见访问问题说明,帮助用户快速找到微博官网主页,实现便捷、安全的网页端登录与内容浏览体验。

194

2026.02.13

Flutter跨平台开发与状态管理实战
Flutter跨平台开发与状态管理实战

本专题围绕Flutter框架展开,系统讲解跨平台UI构建原理与状态管理方案。内容涵盖Widget生命周期、路由管理、Provider与Bloc状态管理模式、网络请求封装及性能优化技巧。通过实战项目演示,帮助开发者构建流畅、可维护的跨平台移动应用。

91

2026.02.13

TypeScript工程化开发与Vite构建优化实践
TypeScript工程化开发与Vite构建优化实践

本专题面向前端开发者,深入讲解 TypeScript 类型系统与大型项目结构设计方法,并结合 Vite 构建工具优化前端工程化流程。内容包括模块化设计、类型声明管理、代码分割、热更新原理以及构建性能调优。通过完整项目示例,帮助开发者提升代码可维护性与开发效率。

20

2026.02.13

Redis高可用架构与分布式缓存实战
Redis高可用架构与分布式缓存实战

本专题围绕 Redis 在高并发系统中的应用展开,系统讲解主从复制、哨兵机制、Cluster 集群模式及数据分片原理。内容涵盖缓存穿透与雪崩解决方案、分布式锁实现、热点数据优化及持久化策略。通过真实业务场景演示,帮助开发者构建高可用、可扩展的分布式缓存系统。

54

2026.02.13

c语言 数据类型
c语言 数据类型

本专题整合了c语言数据类型相关内容,阅读专题下面的文章了解更多详细内容。

29

2026.02.12

雨课堂网页版登录入口与使用指南_官方在线教学平台访问方法
雨课堂网页版登录入口与使用指南_官方在线教学平台访问方法

本专题系统整理雨课堂网页版官方入口及在线登录方式,涵盖账号登录流程、官方直连入口及平台访问方法说明,帮助师生用户快速进入雨课堂在线教学平台,实现便捷、高效的课程学习与教学管理体验。

15

2026.02.12

豆包AI网页版入口与智能创作指南_官方在线写作与图片生成使用方法
豆包AI网页版入口与智能创作指南_官方在线写作与图片生成使用方法

本专题汇总豆包AI官方网页版入口及在线使用方式,涵盖智能写作工具、图片生成体验入口和官网登录方法,帮助用户快速直达豆包AI平台,高效完成文本创作与AI生图任务,实现便捷智能创作体验。

598

2026.02.12

PostgreSQL性能优化与索引调优实战
PostgreSQL性能优化与索引调优实战

本专题面向后端开发与数据库工程师,深入讲解 PostgreSQL 查询优化原理与索引机制。内容包括执行计划分析、常见索引类型对比、慢查询优化策略、事务隔离级别以及高并发场景下的性能调优技巧。通过实战案例解析,帮助开发者提升数据库响应速度与系统稳定性。

56

2026.02.12

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
AngularJS教程
AngularJS教程

共24课时 | 3.7万人学习

CSS3实现按钮特效视频教程
CSS3实现按钮特效视频教程

共15课时 | 3.3万人学习

细说PHP第三季
细说PHP第三季

共58课时 | 11.4万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号