之前的文章我们根据源码的分析,弄清了Yii如何处理一次请求,以及根据解析的路由如何调用控制器中的action,那接下来好奇的可能就是,我在控制器action中执行了return $this->render('index'),那render这个方法是如何完成渲染视图文件的工作的?我们继续从源码入手。

1、找到视图文件

先看我们在controller/action中视图渲染的调用:

public function actionIndex()
{
//代码省略
return $this->render('index',[
'model'=>$model
]);
}
1.1、找到render方法

因为所有的控制器类都继承了yii\web\Controller,最终找到render位于yii\web\Controller的父类yii\base\Controller,看定义:

//yii\base\Controller
public function render($view, $params = [])
{
$content = $this->getView()->render($view, $params, $this);
return $this->renderContent($content);
}

可以看到真正的渲染操作并非在controller中处理,而是在view对象中完成的。这里只负责调用:

  • 把视图文件给我渲染好
  • 把渲染好的视图文件放进我定义的布局文件
  • 返回
1.2、获取视图对象

从render方法的设计可以看到Yii2.0中,控制器(C)和视图(V)是完全分离的,各司其职。看$this->getView():

//yii\base\Controller
public function getView()
{
if ($this->_view === null) {
$this->_view = Yii::$app->getView();
}
return $this->_view;
}

Yii::$app,就是我们new Application的时候保存的一个全局application变量,在构造方法中已经保存好了Yii::$app = $this;,可以查看yii\base\Application __construct,不过多描述了。

这样我们知道了Yii::$app->getView(),getView应该位于yii\web\Application,或者其父类中`:

//yii\base\Application
public function getView()
{
return $this->get('view');
}

get方法位于Application的父类yii\di\ServiceLocator,根据源码可以看到,是对当前对象中的两个成员变量$_components$_definitions做了判断,看是否有view这个组件的对象(实例),或者定义(['class'=>'yii\web\view']),有实例则直接返回,否则根据定义创建实例(createObject)返回。

【注】关于$_definitions变量的初始化,其实在new Application的时候,在yii\base\Application__construct构造方法中,调用了preInit,而preInit方法中对核心组件(coreComponents)进行了初始化,这里就包括了'view' => ['class' => 'yii\web\View'],组件的初始化就是这些配置信息保存的过程,主要通过yii\base\Object中的构造方法,调用了Yii::configure($config),configure的过程就是对$_definitions $_components赋值的过程。

最终经过getView(),我们得到的就是一个yii\web\View object

2、渲染视图文件

进入到yii\web\View中的render方法,位于其父类。

//yii\base\View
public function render($view, $params = [], $context = null)
{
$viewFile = $this->findViewFile($view, $context);
return $this->renderFile($viewFile, $params, $context);
}

通过代码可以看到,渲染视图文件的第一步就是找到这个视图文件在磁盘中的文件存储位置(真实路径)。从findViewFile方法寻找路径的过程,也可看出我们的$view参数支持的几种格式。

2.1、$view参数格式

源码不放了,大家对照yii\base\View中的function findViewFile,或看这里

  1. 按照alias别名的方式

    检查$view中是否包含“@”,如果有说明是使用了别名的方法,直接通过Yii::getAlias($view)获取,因为形式是"@backend/views/site/index"这种格式,而在config文件夹下的bootstrap.php中已经对backend进行了setAlias,所以通过getAias简单处理就可返回真实路径了
  2. 以"//"开头的$view,如"//site/index"

    匹配到这种形式执行Yii::$app->getViewPath(),getViewPath方法事实上是:获取我们在配置文件中定义的basePath,再根据Yii2.0中约定的目录结构,加上"/views"返回
  3. 以"/"开头

    相当于绝对路径的方式,在当前控制器所在的module中进行寻找,这个controller对象的module成员保存的是当前控制器所在的module对象,这个保存是在createControllerByID中调用Yii::createObject()的时候进行赋值的。yii\base\Controller中的构造方法有一句:$this->module = $module;
  4. controller对象调用View进行视图渲染时,将对象自身传递给了view,也就是$context,如果这个控制器实现了ViewContextInterface接口(接口中就定义了一个getViewPath方法),那么直接调用控制器的getViewPath
  5. 最后一种情况就是根据当前视图文件的文件路径来返回视图路径(这种应该是在视图文件中渲染其他视图的情况)

【注】2与3其实都是调用yii\base\Module中的getViewPath,getViewPath中调用了getBasePath,区别在于2中用的是Yii::$app 这个对象,Application对象初始化的时候在preInit中已经对将配置文件中的basePath初始化并保存在了$_basePath中;3中getViewPath调用的发起者是controller实例所属的module对象,module对象创建的时候并未初始化$_basePath,所以可以看到getBasePaht中是使用反射的方法获取当前module对象对应文件的路径,进而返回basePath的

2.2、renderFile

renderFile的操作就比较简单了,根据视图文件的后缀来判断是否启用了相应的模板引擎,如Smarty、Twig等,如果都没有那就默认的php文件的方式(renderPhpFile)进行渲染,renderPhpFile的代码非常简单:

public function renderPhpFile($_file_, $_params_ = [])
{
ob_start();
ob_implicit_flush(false);
//将我们render的参数数组extract为本地变量
extract($_params_, EXTR_OVERWRITE);
//require 我们的视图文件
require($_file_);
//清空并返回当前缓冲区的内容
return ob_get_clean();
}

经过以上的分析,一个视图文件的渲染就完成了,而我们的Yii框架中大多使用了布局文件。所以回到yii\base\Controller的render方法中,视图文件渲染之后返回的是一个字符串,保存在了$content中,然后执行了return $this->renderContent($content),这其实就是把视图文件渲染后的结果放到布局中,这也是为什么我们的布局文件中会有这么一行代码:<?=$content?>。renderContent其实就是获取布局文件的路径然后在调用View中的renderFile方法,过程跟视图渲染的过程一样。

至此,Yii2.0视图渲染过程分析完毕。

【附】render渲染代码调用流程

Yii2.0源码阅读-视图(View)渲染过程的更多相关文章

  1. Yii2.0源码阅读-一次请求的完整过程

    Yii2.0框架源码阅读,从请求发起,到结束的运行步骤 其实最初阅读是从yii\web\UrlManager这个类开始看起,不断的寻找这个类中方法的调用者,最终回到了yii\web\Applicati ...

  2. Yii2.0源码阅读-从路由到控制器

    之前的文章弄清了一次请求的开始到结束.主要讲了Yii Applicaton实例的创建.初始化,UrlManager如何返回Yii中的路由信息,到runAction,最后将Response发送给客户端. ...

  3. Yii2.0源码阅读-behavior的实现原理

    Yii2.0中的一个思想就是组件化的思想,所以.大多数的类都直接或间接的继承自yii\base\Component,而组件的三大功能:属性.事件.行为. 行为的目的是为了方便的扩展一个类的功能,而不需 ...

  4. Yii2.0源码阅读-PHP如何与redis通信?

    PHP与Redis可以通过socket进行通信,前提是PHP需要实现Redis的协议 RESP协议描述: 字符串 \r\n : 表示一个正确的状态信息,具体信息是'+'后面的字符(Simple Str ...

  5. Yii2.0源码分析之——控制器文件分析(Controller.php)创建动作、执行动作

    在Yii中,当请求一个Url的时候,首先在application中获取request信息,然后由request通过urlManager解析出route,再在Module中根据route来创建contr ...

  6. Vue.js 2.0源码解析之前端渲染篇

    一.前言 Vue.js框架是目前比较火的MVVM框架之一,简单易上手的学习曲线,友好的官方文档,配套的构建工具,让Vue.js在2016大放异彩,大有赶超React之势.前不久Vue.js 2.0正式 ...

  7. 【原创】backbone1.1.0源码解析之View

    作为MVC框架,M(odel)  V(iew)  C(ontroler)之间的联系是必不可少的,今天要说的就是View(视图) 通常我们在写逻辑代码也好或者是在ui组件也好,都需要跟dom打交道,我们 ...

  8. Vue2.0源码阅读笔记--双向绑定实现原理

    上一篇 文章 了解了Vue.js的生命周期.这篇分析Observe Data过程,了解Vue.js的双向数据绑定实现原理. 一.实现双向绑定的做法 前端MVVM最令人激动的就是双向绑定机制了,实现双向 ...

  9. Vue2.0源码阅读笔记(二):响应式原理

      Vue是数据驱动的框架,在修改数据时,视图会进行更新.数据响应式系统使得状态管理变的简单直接,在开发过程中减少与DOM元素的接触.而深入学习其中的原理十分有必要,能够回避一些常见的问题,使开发变的 ...

随机推荐

  1. python scipy计算机数值库

    scripy有聚类的python 代码,如: http://blog.csdn.net/elaine_bao/article/details/50242867

  2. JavaScript基础5——关于ECMAscript的函数

    ECMAScript的函数概述(一般定义到<head>标签之间) (1)定义函数,JavaScript一般有三种定义函数方法: *第一种是使用function语句定义函数(静态方法) fu ...

  3. Data Base mongodb driver2.5环境注意事项

    mongodb driver2.5环境注意事项 一.问题: 如果使用vs2012开发就会报这个错误: 未能加载文件或程序集“System.Runtime.InteropServices.Runtime ...

  4. 【Zookeeper】源码分析之服务器(三)之LeaderZooKeeperServer

    一.前言 前面分析了ZooKeeperServer源码,由于QuorumZooKeeperServer的源码相对简单,于是直接分析LeaderZooKeeperServer. 二.LeaderZooK ...

  5. 手动安装cloudera manager 5.x(tar包方式)详解

    官方共给出了3中安装方式:第一种方法必须要求所有机器都能连网,由于最近各种国外的网站被墙的厉害,我尝试了几次各种超时错误,巨耽误时间不说,一旦失败,重装非常痛苦.第二种方法下载很多包.第三种方法对系统 ...

  6. bzoj 4237: 稻草人

    Description JOI村有一片荒地,上面竖着N个稻草人,村民们每年多次在稻草人们的周围举行祭典. 有一次,JOI村的村长听到了稻草人们的启示,计划在荒地中开垦一片田地.和启示中的一样,田地需要 ...

  7. 视频云SDK iOS持续集成项目实践

    1. 前言 2016年, 我们维护的 iOS推流播放融合SDK KSYLive_iOS 在github上发布了40多个版本, 平均两周发布一个新版本, 经历了最初痛苦的全手动版本构建和维护, 到后来慢 ...

  8. 用Go校验下载文件之SHA256

    用GO校验下载文件之SHA256 原来对计算机和网络使用安全这块不够重视,用了N多年盗版的操作系统和办公软件,为了破解使用过各种激活软件,也安装使用过很多别人破解过的软件:网络下载的文件从不校验.慢慢 ...

  9. 一、源代码-面向CLR的编译器-托管模块-(元数据&IL代码)

    本文脉络图如下: 1.CLR(Common Language Runtime)公共语言运行时简介 (1).公共语言运行时是一种可由多种编程语言一起使用的"运行时". (2).CLR ...

  10. vim置于后台,vim 编辑多文件

    这里介绍一个很实用的方法:1.将vim置于后台,直接按 ctrl + z可以将当前的vim置于后台 2.然后可以去别的目录再打开一个 当你需要打开之前的vim的时候3.打jobs命令看当前有哪些vim ...