Yii框架页面渲染操作实例详解


Posted in PHP onJuly 19, 2019

本文实例讲述了Yii框架页面渲染操作。分享给大家供大家参考,具体如下:

1、一般页面渲染

yii的页面渲染通过在controller的action中调用$this->render($viewname...)进行,流程如下图:

Yii框架页面渲染操作实例详解

在render方法中,yii会先对你的view文件进行渲染,然后如果你使用了某些layouts,则会将view渲染的输出再传入对layouts的渲染方法中,上述这两步在虚线框中表示了,简单的页面渲染就是这样的。

当然这里面有些技巧需要注意,首先是黑框中显示的那几行代码(位于renderInternal方法中),yii首先启用输出缓冲,并禁止隐式的冲掉缓冲,然后require需要渲染的视图文件,最后再获取缓冲区的全部内容,即最终的渲染结果。这样处理有3个好处:

1.视图文件中多次echo也必须最后一起输出;

2.可以在视图文件中使用$this,即当前的controller对象。

3.第三个好处是这样的,黑框中漏掉了一句“extract($_data_,EXTR_PREFIX_SAME,'data');”,extract函数的作用是将$_data_数组中的$key=>$value对变成当前作用域中的$key = $value赋值,这样视图文件中就可以直接使用$key引用$value的值了。不知道smarty中变量赋值是怎么进行的,但是感觉yii这种方式高效很多,因为不再需要使用php实现词法分析之类的功能了。

这个技巧我们可以自己简单实现一下,就会明白它的原理了。编写代码如下:

class Controller
{
 private $name='';
 public function __construct($name)
 {
  $this->name = $name;
 }
 public function render($viewName, $data)
 {
  extract($data, EXTR_PREFIX_SAME,'data');
  ob_start();
  ob_implicit_flush(0);
  require($viewName . '.php');
  echo ob_get_clean();
 }
}
$ctrl = new Controller('php');
$ctrl->render('view', array('age'=>20)); //模仿render方法调用
echo $this->name . "\n" . $age . "\n"; //view.php只有一句

假设第一段代码存为controller.php,第二段存为view.php(若存为其他名字,请相应修改调用render时传入的名字),在终端执行php controller.php会输出:

php
20

本来view.php中是没有$this和$age的,但是因为require时给予了它render方法的作用域,并且采用了extract方法操作传入的数组参数,使得读取这两个变量成为可能。

2、嵌套了layout的视图文件的渲染

这里嵌套是指controller采用了layout1并渲染视图view,而layout1又采用了布局layout2。采用layout1并渲染view是上

一部分的内容,而在layout1中采用layout2是这部分要讲的。采用这种方式进行渲染,通常需要在layout1中调用

controller的beginContent(layout2)方法,并传入layout2的名称,然后在渲染结束后再调用controller的endContent()

方法结束渲染过程。伪码如下:

<?php
// $this is the controller
$this->beginContent('layout2');
?>
some html and/or <?php echo $content; ?>
<?php $this->endContent(); ?>

这里就要讲这两个方法以及整个过程的实现机制。先来看beginContent的工作流程:

Yii框架页面渲染操作实例详解

请注意这一连串的过程都是在当前controller的作用域进行的。可以看到beginContent调用beginWidget并传入了一个类名,这个类的实例就是后面的widget,表示了一个装饰器,注意在createWidget时传入了当前controller的实例,并且会对widget的view属性赋值为layout名称(这里的过程还要稍微复杂些,但是大致的意图是这样的,具体可参考源码),这两个变量后面有用;然后调用widget的Init方法使其初始化,并将其缓存到controller的一个stack中。值得注意的是init方法里做了什么:很熟悉,打开了输出缓冲区。用途是什么,看了第一部分你应该懂~~下面再看endContent的执行过程:

Yii框架页面渲染操作实例详解

这个过程稍微复杂些,先说明一直到第一个虚线框(包括)都是在当前controller的作用域,之后都是在widget的作用域了。可以看到调用endContent之后其实先从controller的那个stack中弹出了先前保存的widget,然后调用widget的run方法。之后就主要是widget的工作了,首先是熟悉的ob_get_clean()拿到缓冲区中的内容,参考伪码你会明白,此时缓冲区中的内容是“some html and/or ...”,即你写的页面html和要echo出的东西;然后重要的工作在decorate方法中,它会通知controller去获取layout文件,并通知controller渲染这个文件,但是controller在哪儿?就是widget的owner属性,表示谁拥有这个widget,还记得在beginContent中向widget实例传入了controller对象吧?:) 之后的过程就简单了,跟渲染普通视图文件一样,只不过这里会将从缓冲区得到的内容全部传给视图文件,并获取最终的渲染结果。

同样的,我们也可以写个demo模拟这个渲染过程,编写代码如下:

<?php
class Decorator
{
 public function begin()
 {
  ob_start();
  ob_implicit_flush(0);
 }
 public function decorate($content)
 {
  echo 'from Decorator ' . $content;
 }
 public function end()
 {
  $output = ob_get_clean();
  $this->decorate($output);
 }
}
?>
require_once('dec.php');
$dec = new Decorator();
$dec->begin();
?>
<h1>sddfds</h1>
<?php echo 'hello'; ?>
<?php $dec->end(); ?>

假设第一段代码为dec.php表示装饰器,第二段为layout.php,表示布局文件,运行php layout.php应该会输出:

from Decorator
<h1>sddfds</h1>
hello

这个简化的过程能方便理解框架里的渲染流程。

3、总结

yii的两种渲染过程都有效的利用了语言的输出缓冲,而第二种方式更是通过将“开缓冲”和“取缓冲”的操作分离开,进而实现了对这两个操作之间的输出内容进行装饰的功能

希望本文所述对大家基于Yii框架的PHP程序设计有所帮助。

PHP 相关文章推荐
学习使用PHP数组
Oct 09 PHP
无法在发生错误时创建会话,请检查 PHP 或网站服务器日志,并正确配置 PHP 安装最快的解决办法
Aug 01 PHP
php批量缩放图片的代码[ini参数控制]
Feb 11 PHP
PHP+Mysql+jQuery实现发布微博程序 jQuery篇
Oct 08 PHP
php数组函数序列之array_unshift() 在数组开头插入一个或多个元素
Nov 07 PHP
PHP去掉从word直接粘贴过来的没有用格式的函数
Oct 29 PHP
使用PHP实现蜘蛛访问日志统计
Jul 05 PHP
DOM XPATH获取img src值的query
Sep 23 PHP
PHP面向对象教程之自定义类
Jun 10 PHP
php查找字符串出现次数的方法
Dec 01 PHP
PHP基于redis计数器类定义与用法示例
Feb 08 PHP
yii2.0框架使用 beforeAction 防非法登陆的方法分析
Sep 11 PHP
Yii2 queue的队列使用详解
Jul 19 #PHP
thinkphp5.1框架模板布局与模板继承用法分析
Jul 19 #PHP
Yii2.0框架模型添加/修改/删除数据操作示例
Jul 18 #PHP
Yii2.0框架模型多表关联查询示例
Jul 18 #PHP
php和redis实现秒杀活动的流程
Jul 17 #PHP
php web环境和命令行环境下查找php.ini的位置
Jul 17 #PHP
php命名空间设计思想、用法与缺点分析
Jul 17 #PHP
You might like
基于qmail的完整WEBMAIL解决方案安装详解
2006/10/09 PHP
网站用php实现paypal整合方法
2010/11/28 PHP
解析用PHP读写音频文件信息的详解(支持WMA和MP3)
2013/05/10 PHP
php中error与exception的区别及应用
2014/07/28 PHP
PHP HTTP 认证实例详解
2016/11/03 PHP
PHP中ajax无刷新上传图片与图片下载功能
2017/02/21 PHP
Laravel框架自定义验证过程实例分析
2019/02/01 PHP
通过 Dom 方法提高 innerHTML 性能
2008/03/26 Javascript
js获取本机的外网/广域网ip地址完整源码
2013/08/12 Javascript
js电话号码验证方法
2015/09/28 Javascript
学习JavaScript设计模式(策略模式)
2015/11/26 Javascript
论JavaScript模块化编程
2016/03/07 Javascript
Javascript打印局部页面实例
2016/06/21 Javascript
bootstrap选项卡使用方法解析
2017/01/11 Javascript
Linux系统中利用node.js提取Word(doc/docx)及PDF文本的内容
2017/06/17 Javascript
原生js的ajax和解决跨域的jsonp(实例讲解)
2017/10/16 Javascript
nuxt.js写项目时增加错误提示页面操作
2020/11/05 Javascript
python使用Image处理图片常用技巧分析
2015/06/01 Python
python学习之matplotlib绘制散点图实例
2017/12/09 Python
Python+selenium实现自动循环扔QQ邮箱漂流瓶
2018/05/29 Python
对Python 数组的切片操作详解
2018/07/02 Python
Python get获取页面cookie代码实例
2018/09/12 Python
python与字符编码问题
2019/05/24 Python
使用python 写一个静态服务(实战)
2019/06/28 Python
python实现的发邮件功能示例
2019/09/11 Python
Python实现CAN报文转换工具教程
2020/05/05 Python
实例讲解CSS3中的box-flex弹性盒属性布局
2016/06/09 HTML / CSS
Bootstrap File Input文件上传组件
2020/12/01 HTML / CSS
工商学院毕业生个人自我评价
2013/09/19 职场文书
新娘父亲婚礼致辞
2014/01/16 职场文书
纪念九一八事变演讲稿1000字
2014/09/14 职场文书
小班上学期个人总结
2015/02/12 职场文书
莫言诺贝尔获奖感言(全文)
2015/07/31 职场文书
中秋节主题班会
2015/08/14 职场文书
5个实用的JavaScript新特性
2022/06/16 Javascript
python数据分析之单因素分析线性拟合及地理编码
2022/06/25 Python