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控制用户的浏览器--ob*函数的使用说明
Mar 16 PHP
php error_log 函数的使用
Apr 13 PHP
mysql_fetch_row,mysql_fetch_array,mysql_fetch_assoc的区别
Apr 24 PHP
ajax返回值中有回车换行、空格的解决方法分享
Oct 24 PHP
PHP+Ajax检测用户名或邮件注册时是否已经存在实例教程
Aug 23 PHP
php中socket的用法详解
Oct 24 PHP
PHP处理大量表单字段的便捷方法
Feb 07 PHP
PHP控制前台弹出对话框的实现方法
Aug 21 PHP
php版微信自动登录并获取昵称的方法
Sep 23 PHP
PHP-CGI远程代码执行漏洞分析与防范
May 07 PHP
详解yii2使用多个数据库的案例
Jun 16 PHP
PHP Include文件实例讲解
Feb 15 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
【COS正片】蕾姆睡衣cos,纯洁可爱被治愈了 cn名濑弥七
2020/03/02 日漫
mysql 字段类型说明
2007/04/27 PHP
Linux下 php5 MySQL5 Apache2 phpMyAdmin ZendOptimizer安装与配置[图文]
2008/11/18 PHP
PHP对象Object的概念 介绍
2012/06/14 PHP
php跨服务器访问方法小结
2015/05/12 PHP
11款基于Javascript的文件管理器
2009/10/25 Javascript
jquery EasyUI的formatter格式化函数代码
2011/01/12 Javascript
jquery实现pager控件示例
2014/04/09 Javascript
检测一个函数是否是JavaScript原生函数的小技巧
2015/03/13 Javascript
JQuery+EasyUI轻松实现步骤条效果
2016/02/22 Javascript
js 实现数值的千分位及保存小数方法(推荐)
2016/08/01 Javascript
如何将你的AngularJS1.x应用迁移至React的方法
2018/02/01 Javascript
Vue 项目代理设置的优化
2018/04/17 Javascript
js实现简单模态框实例
2018/11/16 Javascript
vue.js实现的幻灯片功能示例
2019/01/18 Javascript
JavaScript数据结构与算法之检索算法示例【二分查找法、计算重复次数】
2019/02/22 Javascript
vue 实现Web端的定位功能 获取经纬度
2019/08/08 Javascript
node 文件上传接口的转发的实现
2019/09/23 Javascript
JavaScript 函数用法详解【函数定义、参数、绑定、作用域、闭包等】
2020/05/12 Javascript
JavaScript indexOf()原理及使用方法详解
2020/07/09 Javascript
python批量修改文件名的实现代码
2014/09/01 Python
Python的字典和列表的使用中一些需要注意的地方
2015/04/24 Python
OpenCV搞定腾讯滑块验证码的实现代码
2019/05/18 Python
Python3批量生成带logo的二维码方法
2019/06/24 Python
python批量处理文件或文件夹
2020/07/28 Python
浅谈JupyterNotebook导出pdf解决中文的问题
2020/04/22 Python
python+selenium+chrome批量文件下载并自动创建文件夹实例
2020/04/27 Python
毕业生教师求职信
2013/10/20 职场文书
日语求职信范文
2013/12/17 职场文书
2014班子“三严三实”对照检查材料思想汇报
2014/09/18 职场文书
群众路线教育实践活动调研报告
2014/11/03 职场文书
人生一定要学会的三样东西:放下、忘记、珍惜
2019/08/21 职场文书
Requests什么的通通爬不了的Python超强反爬虫方案!
2021/05/20 Python
Python干货实战之八音符酱小游戏全过程详解
2021/10/24 Python
解决redis批量删除key值的问题
2022/03/23 Redis
Golang 入门 之url 包
2022/05/04 Golang