`

Yii分析9:CController控制视图(Cview)的展现

 
阅读更多

 

    《The Definitive Guide to Yii》描述了视图的概念:“视图是一个包含了主要的用户交互元素的PHP脚本.他可以包含PHP语句”,不同于很多类似的框架,Yii并没有使用smarty作为模板引擎,而是直接使用原生的PHP脚本作为模板,笔者认为至少有以下两点好处:

  (1) 门槛低,易于使用,不需要理解和记忆smarty的模板语言语法

  (2) 减少了模板引擎解析的过程,直接include,结合opcode缓存,效率可能会更高

当然也有缺点:

  (1) 没有smarty的前端过滤功能,前后端分离开发也有一定的门槛(前端工程师需要学习PHP语法,尤其是字符串处理相关函数)

  (2) 直接使用PHP,对于一些约束很难控制,比如全局的错误级别,如何控制逻辑处理与数据处理的界限?

      因此,对于是使用PHP原生脚本还是使用smarty作为模板各有利弊,不论程序开发人员使用哪一种,都要了解这种方式的利弊才能更加安全有效地进行开发。

 

在Yii中,显示一个视图非常简单,即调用Ccontroller的方法render:

 

$this->render(‘viewName’);

 

 而这个过程是如何实现的呢?我们看看render这个方法的源码:

 

/**
	 * 使用框架来渲染一个视图
	 *
	 * 这个方法首先调用{@link renderPartial}来渲染视图 (内容视图)
	 * 然后渲染框架视图(在合适的位置嵌入内容视图)
	 * 在框架视图中,内容视图的渲染结果以变量的方式来访问
	 * 最后,调用{@link processOutput}在可用时来插入脚本
	 * 和动态内容
	 *
	 * 默认的框架视图位置为:"protected/views/layouts/main.php".
	 * 可以通过设置{@link layout}.来自定义
	 *
	 * @param string $view 要被渲染的视图名称See {@link getViewFile} for details
	 * about how the view script is resolved.
	 * @param array $data 在视图中被解析为PHP变量的数据
	 * @param boolean $return 返回渲染的结果或者直接显示给最终用户
	 * @return string the rendering result. Null if the rendering result is not required.
	 * @see renderPartial
	 * @see getLayoutFile
	 */
	public function render($view,$data=null,$return=false)
	{
		//触发beforeRender事件,beforeRender直接返回true(子类覆盖自定义)
		if($this->beforeRender($view))
		{
			//将$view的内容渲染后返回给变量$output
			$output=$this->renderPartial($view,$data,true);
			if(($layoutFile=$this->getLayoutFile($this->layout))!==false)
				//将$output作为数据渲染整个框架
				$output=$this->renderFile($layoutFile,array('content'=>$output),true);
			//afterRender是一个空函数,子类覆盖自定义
			$this->afterRender($view,$output);
			
			//处理输出
			$output=$this->processOutput($output);

			//返回or直接输出
			if($return)
				return $output;
			else
				echo $output;
		}
	}

 

 

      在render的过程中,用到了另外render函数:renderPartial和renderFile,renderPartial是CController的一个成员函数:

 

 

/**
	 * 渲染一个视图
	 *
	 * 视图名,指向一个PHP脚本通过{@link getViewFile}解析
	 * 如果$data是一个数组,会被解析为PHP的变量
	 * 可以在视图脚本中使用
	 *
	 * 这个方法不同于{@link render(),他不会使用框架(layout)来渲染
	 * 常用来渲染一个视图的一部分,或者AJAX响应
	 *
	 * @param string $view 被渲染的视图名称{@link getViewFile}
	 * @param array $data 被解析为PHP变量的数据,在视图脚本中可用
	 * @param boolean $return 渲染的结果是否被返回,否则直接展示给最终用户
	 * @param boolean $processOutput 是否使用{@link processOutput}来处理渲染结果
	 * @return string 渲染结果
	 * @throws CException 如果视图不存在会抛出异常
	 * @see getViewFile
	 * @see processOutput
	 * @see render
	 */
	public function renderPartial($view,$data=null,$return=false,$processOutput=false)
	{
		//获取视图路径
		if(($viewFile=$this->getViewFile($view))!==false)
		{
			//调用renderFile来返回渲染结果
			$output=$this->renderFile($viewFile,$data,true);
			if($processOutput)
				$output=$this->processOutput($output);
			//返回or直接显示
			if($return)
				return $output;
			else
				echo $output;
		}
		else
			throw new CException(Yii::t('yii','{controller} cannot find the requested view "{view}".',
				array('{controller}'=>get_class($this), '{view}'=>$view)));
	}

 

 renderFile并不是在CController中定义的,而是在CController的父类CBaseController中定义:

       /**
	 * 渲染一个视图文件
	 *
	 * @param string $viewFile 视图文件路径view file path
	 * @param array $data 解析为变量的数据
	 * @param boolean $return 是否返回渲染结果
	 * @return string 渲染结果
	 * @throws CException if the view file does not exist
	 */
	public function renderFile($viewFile,$data=null,$return=false)
	{
		$widgetCount=count($this->_widgetStack);
		//获取renderer类,同时检查视图文件扩展名,默认情况下,是没有自定义的viewRenderer对象的,Yii内置了抽象类CViewRenderer,如果自定义可以继承这个类
		if(($renderer=Yii::app()->getViewRenderer())!==null && $renderer->fileExtension==='.'.CFileHelper::getExtension($viewFile))
			//如果renderer的扩展名与视图文件扩展名相同
			$content=$renderer->renderFile($this,$viewFile,$data,$return);
		else
			//调用renderInternal
			$content=$this->renderInternal($viewFile,$data,$return);
		//使用widget的堆栈计数,如果与widgetCount不一致,说明没有调用endWidget()来释放
		if(count($this->_widgetStack)===$widgetCount)
			return $content;
		else
		{
			$widget=end($this->_widgetStack);
			throw new CException(Yii::t('yii','{controller} contains improperly nested widget tags in its view "{view}". A {widget} widget does not have an endWidget() call.',
				array('{controller}'=>get_class($this), '{view}'=>$viewFile, '{widget}'=>get_class($widget))));
		}
	}

 renderInternal代码如下:

        public function renderInternal($_viewFile_,$_data_=null,$_return_=false)
	{
		// we use special variable names here to avoid conflict when extracting data
		if(is_array($_data_))
			//如果data是数组,使用extract
			extract($_data_,EXTR_PREFIX_SAME,'data');
		else
			//如果不是数组,直接赋给$data变量
			$data=$_data_;
		//如果需要返回,使用ob进行缓冲输出,之后再返回,否则直接调用require(如果文件不存在,会导致一个fatal error)
		if($_return_)
		{
			ob_start();
			ob_implicit_flush(false);
			require($_viewFile_);
			return ob_get_clean();
		}
		else
			require($_viewFile_);
	}

 接着,我们来看一下在渲染玩view文件之后,处理输出的过程:

 

        /**
	 *由{@link render()}调用处理最后的输出
	 * 这个方法在{@link render()}和{@link renderText()}的结尾调用
	 * 如果有注册的客户端脚本,这个方法会把他们在合适的位置
	 * 插入到输出中。如果有动态内容,也会被插入
	 * 这个方法可能会在页面的隐藏状态窗口中保存页面的持久状态
	 * @param string $output 由当前action产生的输出
	 * @return string 处理过的输出
	 */
	public function processOutput($output)
	{
		//插入客户端脚本
		Yii::app()->getClientScript()->render($output);

		// 如果使用了页面缓存,我们可以延迟动态内容的替换
		if($this->_dynamicOutput!==null && $this->isCachingStackEmpty())
			$output=$this->processDynamicOutput($output);
		
		//页面状态的处理
		if($this->_pageStates===null)
			$this->_pageStates=$this->loadPageStates();
		if(!empty($this->_pageStates))
			$this->savePageStates($this->_pageStates,$output);

		return $output;
	}
	public function processDynamicOutput($output)
	{
		if($this->_dynamicOutput)
		{
			//使用正则替换特殊字符
				$output=preg_replace_callback('/<###dynamic-(\d+)###>/',array($this,'replaceDynamicOutput'),$output);
		}
		return $output;
	}
 

     至此,整个render过程已经完成,总结下来,主要经历了数据解析和require,加载客户端脚本和动态数据两部分。

 

3
1
分享到:
评论
2 楼 silentime 2011-12-13  
z.y.f 写道
先赞一个~感觉smarty本身在前后端开发分离上的作用不大,倒是可以防止出现view层出现过多的逻辑代码,可以规范一下view代码,使之只负责数据展示。。。

1 楼 z.y.f 2011-12-10  
先赞一个~感觉smarty本身在前后端开发分离上的作用不大,倒是可以防止出现view层出现过多的逻辑代码,可以规范一下view代码,使之只负责数据展示。。。

相关推荐

    PHP的Yii框架中创建视图和渲染视图的方法详解_.docx

    控制器渲染的视图文件通常位于`@app/views/ControllerID`目录下,其中`ControllerID`对应控制器的ID。例如,如果控制器类是`PostController`,视图文件应该位于`@app/views/post`。对于模块中的控制器,视图文件会在...

    yii-passport:使Laravel Passport与Yii一起工作

    Yii护照 安装 :light_bulb: 这是展示如何安装软件包的好地方,请参见下文: 跑步 $ composer require inquid/yii-passport 用法 :light_bulb: 这是显示一些用法示例的好地方! 变更日志 请看看 。 贡献 请看看 。...

    yii2elfinder:yii2elfinder

    yii2elfinder 感谢: : 感谢:zybodya 提供当前 yii 版本 yii2elfinder 介绍:旧版本无法使用,因为它完全不适用于最新的jquery版本! 所以除了行动,我不得不改变一切;) 这个扩展允许你将 ElFinder 文件管理...

    yii-haml:Yii 框架的 HAML 视图渲染器

    Yii 框架的 HAML 视图渲染器 yii-haml是扩展,它为您的视图带来了功能。 基于项目的分支。 使用 Composer 安装 将此添加到您的composer.json : " repositories " : [ { " type " : " composer " , " url " : ...

    php yii源码分析

    Yii 实现了 MVC 设计模式,模型(Model)负责数据和业务逻辑,视图(View)负责展示数据,控制器(Controller)负责接收用户请求并调用模型处理数据,最后将结果传递给视图进行渲染。在源码中,你可以看到如何通过...

    Yii框架快速入门

    Yii的设计遵循面向对象编程原则,完全基于MVC(Model-View-Controller)架构,这使得开发者能够清晰地分离业务逻辑、数据管理和用户界面,从而促进代码的重用性和维护性。 #### 二、MVC架构解析 MVC架构,即模型-...

    yii2sly:jquery 狡猾

    yii2sly 这个扩展是惊人的 jquery 滑块“sly”的包装器,可以在这里找到: 请。 仔细查看所有插件选项,可以通过将它们添加到“clientOptions”参数来传递这些选项,如下所示。 可以在此处找到扩展的演示: 安装 ...

    YII2框架代码

    它包含一个单一的应用入口文件,所有的控制器、模型和视图都放在同一个目录下,适合初学者快速了解YII2的基本操作。 2. 高级版YII2框架:适用于大型复杂的Web应用程序,提供了更清晰的模块化结构和多应用支持。高级...

    yii-demo:Yii 框架扩展的演示

    在 "yii-demo" 中,你可以看到模型类(Model)处理数据逻辑,视图(View)负责渲染用户界面,而控制器(Controller)则协调模型和视图之间的交互。 2. **组件系统**:Yii 提供了强大的组件化设计,允许开发者自定义...

    yii-simplepie:Yii1.* 的 RSS 解析扩展

    yii-simplepie yii-simplepie 是用于解析 rss 提要的 yii 扩展: 简单派: simplepie 文档: 用法 在 yii 中安装扩展 下载所有文件并放入 yii 扩展文件夹,然后在 config/main.php 中添加以下代码 'simplepie' ...

    yii-qa:基于Yii2实现的问答系统

    Yii-QA简介(此项目目前已不再维护)感谢选择Yii-QA,基于框架基础实现的问答程序。 #意识到目前的急性时间有限,无法管理太多的额外项目,我准备合并现有手上的项目,集成在一个项目中,感谢支持!!!!!!!请关注:...

    yii-robokassa:用于与 Robokassa 支付服务的 api 配合使用的 Yii 组件

    用于与支付的 api 配合使用的 Yii 组件 安装 从这个 github 存储库下载 yii-robokassa: cd protected/components git clone https://github.com/ladamalina/yii-robokassa.git 在 protected/config/main.php 中...

    Yii控制器中操作视图js的方法

    Yii框架是一个流行的PHP开发框架,它提供了一套丰富的功能,用于开发...总而言之,Yii控制器提供了丰富的API来操作视图中的js,使得开发者能够灵活地控制页面行为和交互,从而创建出既美观又具有高用户体验的应用程序。

    yii-commentator:Yii评论模块

    **Yii评论模块详解** Yii评论模块,名为"yii-commentator",是一款专为Yii框架设计的评论系统插件。Yii,作为一个高效的PHP框架,广泛应用于Web应用开发,而"yii-commentator"则为Yii框架提供了方便、灵活的评论...

    yii-seo:Yii PHP 框架的搜索引擎优化

    yii-seo Yii PHP 框架的搜索引擎优化。 用法 布局中 &lt;?php Yii::app()-&gt;controller-&gt;widget( 'vendor.crisu83.yii-seo.widgets.SeoHead', array( 'httpEquivs' =&gt; array( 'Content-Type' =&gt; 'text/html; ...

    The Yii Book: Developing Web Applications Using the Yii PHP Framework(Part1&2)

    2. **MVC架构**:Model-View-Controller模式在Yii中的实现,如何创建和组织控制器、模型和视图。 3. **数据库操作**:使用Gii工具自动生成模型和CRUD操作,DAO和ActiveRecord的概念及其使用方法。 4. **表单处理**:...

    yii-ckeditor:简单的 Yii 框架 CKEditor 小部件

    Yii 框架的 CKEditor 小部件 简单的 Yii CKEditor 小部件。 CKEditor - 每个人的 WYSIWYG 编辑器。 小部件生成具有相同属性的 CHtml::activeTextArea。 使用 CKEditor 4+ 版本测试。 安装 将此小部件复制到扩展...

    yii-streamlog:将 Yii 1 日志发送到 stdoutstderr - 创建用于与 http 上提供的 php-fpmnginx Docker 堆栈一起使用

    Yii 1 流日志 将 Yii 1 日志发送到 stdout/stderr - 创建用于与提供的 php-fpm/nginx Docker 堆栈一起使用 感谢 Haensel 为! 安装 通过作曲家安装: composer require neam/yii-streamlog:* 或者下载扩展,将src...

Global site tag (gtag.js) - Google Analytics