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 相关文章推荐
实用函数3
Nov 08 PHP
解析如何屏蔽php中的phpinfo()函数
Jun 06 PHP
zf框架的Filter过滤器使用示例
Mar 13 PHP
PHP将session信息存储到数据库的类实例
Mar 04 PHP
PHP CURL 多线程操作代码实例
May 13 PHP
一个PHP实现的轻量级简单爬虫
Jul 08 PHP
php文件上传的两种实现方法
Apr 04 PHP
PHP加密解密类实例代码
Jul 20 PHP
php静态成员方法和静态的成员属性的使用方法
Oct 26 PHP
php生成复杂验证码(倾斜,正弦干扰线,黏贴,旋转)
Mar 12 PHP
PHP Trait功能与用法实例分析
Jun 03 PHP
windows系统php环境安装swoole具体步骤
Mar 04 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
超级简单的发送邮件程序
2006/10/09 PHP
基于mysql的bbs设计(二)
2006/10/09 PHP
PHP 命令行参数详解及应用
2011/05/18 PHP
使用PHP实现阻止用户上传成人照片或者裸照
2014/12/25 PHP
一个非常完美的读写ini格式的PHP配置类分享
2015/02/12 PHP
用PHP将Unicode 转化为UTF-8的实现方法(推荐)
2017/02/08 PHP
jquery 跨域访问问题解决方法(笔记)
2011/06/08 Javascript
javascript高级学习笔记整理
2011/08/14 Javascript
js实现屏蔽默认快捷键调用自定义事件示例
2013/06/18 Javascript
js实现的类似于asp数据字典的数据类型代码实例
2014/09/03 Javascript
几种响应式文字详解
2017/05/19 Javascript
JS库之wow.js使用方法
2017/09/14 Javascript
AngularJS的$location使用方法详解
2017/10/19 Javascript
在Vue中获取组件声明时的name属性方法
2018/09/12 Javascript
jQuery实现侧边栏隐藏与显示的方法详解
2018/12/22 jQuery
基于vue如何发布一个npm包的方法步骤
2019/05/15 Javascript
微信小程序使用npm包的方法步骤
2019/08/13 Javascript
浅谈Node新版本13.2.0正式支持ES Modules特性
2019/11/25 Javascript
vue设置全局访问接口API地址操作
2020/08/14 Javascript
python操作MySQL数据库具体方法
2013/10/28 Python
Python Trie树实现字典排序
2014/03/28 Python
python增加矩阵维度的实例讲解
2018/04/04 Python
解决Python2.7读写文件中的中文乱码问题
2018/04/12 Python
Python3实现的字典遍历操作详解
2018/04/18 Python
python生成多个只含0,1元素的随机数组或列表的实例
2018/11/12 Python
Python提取特定时间段内数据的方法实例
2019/04/01 Python
如何用Python制作微信好友个性签名词云图
2019/06/28 Python
Python中if有多个条件处理方法
2020/02/26 Python
在python中利用dict转json按输入顺序输出内容方式
2020/02/27 Python
ZWILLING双立人英国网上商店:德国刀具锅具厨具品牌
2018/05/15 全球购物
Ray-Ban雷朋太阳眼镜英国官网:Ray-Ban UK
2019/11/23 全球购物
shell的种类有哪些
2015/04/15 面试题
面试后的英文感谢信
2014/02/01 职场文书
致垒球运动员加油稿
2014/02/16 职场文书
召开会议通知范文
2015/04/15 职场文书
2019最新企业员工考勤管理制度(通用版)!
2019/07/02 职场文书