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截取utf-8中文字符串乱码的解决方法
Mar 29 PHP
apache+php+mysql安装配置方法小结
Aug 01 PHP
浅谈php serialize()与unserialize()的用法
Jun 05 PHP
Laravel 5 框架入门(二)构建 Pages 的管理功能
Apr 09 PHP
smarty中常用方法实例总结
Aug 07 PHP
yii2中的rules 自定义验证规则详解
Apr 19 PHP
php把字符串指定字符分割成数组的方法
Mar 12 PHP
PHP操作Postgresql封装类与应用完整实例
Apr 24 PHP
php对象工厂类完整示例
Aug 09 PHP
PHP封装的验证码工具类定义与用法示例
Aug 22 PHP
PHP的PDO预处理语句与存储过程
Jan 27 PHP
如何通过Apache在本地配置多个虚拟主机
Jul 29 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
PHP 上传文件的方法(类)
2009/07/30 PHP
简单的php中文转拼音的实现代码
2014/02/11 PHP
浅析Yii2 gridview实现批量删除教程
2016/04/22 PHP
js href的用法
2010/05/13 Javascript
safari,opera嵌入iframe页面cookie读取问题解决方法
2010/06/23 Javascript
jQuery timers计时器简单应用说明
2010/10/28 Javascript
原生Js实现元素渐隐/渐现(原理为修改元素的css透明度)
2013/06/24 Javascript
jQuery标签替换函数replaceWith()的使用例子
2014/08/28 Javascript
Web打印解决方案之普通报表打印功能
2016/08/29 Javascript
Jquery通过ajax请求NodeJS返回json数据实例
2016/11/08 NodeJs
纯html+css+javascript实现楼层跳跃式的页面布局(实例代码)
2017/10/25 Javascript
了解ESlint和其相关操作小结
2018/05/21 Javascript
jquery拖拽自动排序插件使用方法详解
2020/07/20 jQuery
判断文字超过2行添加展开按钮,未超过则不显示,溢出部分显示省略号
2019/04/28 Javascript
php使用递归与迭代实现快速排序示例
2014/01/23 Python
Python配置文件解析模块ConfigParser使用实例
2015/04/13 Python
python基于隐马尔可夫模型实现中文拼音输入
2016/04/01 Python
python3将视频流保存为本地视频文件
2018/06/20 Python
Windows10下 python3.7 安装 facenet的教程
2019/09/10 Python
Python实现串口通信(pyserial)过程解析
2019/09/25 Python
Django ORM filter() 的运用详解
2020/05/14 Python
Python爬虫教程知识点总结
2020/10/19 Python
苏宁红孩子母婴商城:redbaby
2017/02/12 全球购物
会计与审计毕业生自荐信范文
2013/12/30 职场文书
致百米运动员广播稿
2014/01/29 职场文书
资金主管岗位职责范本
2014/03/04 职场文书
乡镇三项教育实施方案
2014/03/30 职场文书
文明城市标语
2014/06/16 职场文书
机电系毕业生求职信
2014/07/11 职场文书
房屋买卖授权委托书
2014/09/27 职场文书
2014年租房协议书范本
2014/10/30 职场文书
2014年个人总结范文
2015/03/09 职场文书
停电调休通知
2015/04/16 职场文书
获奖感言一句话
2015/07/31 职场文书
患者身份识别制度
2015/08/06 职场文书
2016春季小学开学寄语
2015/12/03 职场文书