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中date()日期函数有关参数整理
Jul 19 PHP
php常用Output和ptions/Info函数集介绍
Jun 19 PHP
PHP获取php,mysql,apche的版本信息示例代码
Jan 16 PHP
使用PHPMailer实现邮件发送代码分享
Oct 23 PHP
ThinkPHP处理Ajax返回的方法
Nov 22 PHP
PHP将字符分解为多个字符串的方法
Nov 22 PHP
php实现搜索一维数组元素并删除二维数组对应元素的方法
Jul 06 PHP
4种PHP异步执行的常用方式
Dec 24 PHP
PHP实现数组array转换成xml的方法
Jul 19 PHP
使用ThinkPHP生成缩略图及显示
Apr 27 PHP
thinkphp5框架实现的自定义扩展类操作示例
May 16 PHP
YII2框架中日志的配置与使用方法实例分析
Mar 18 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 的 __FILE__ 常量
2007/01/15 PHP
解析PHP正则提取或替换img标记属性
2013/06/26 PHP
Smarty中的注释和截断功能介绍
2015/04/09 PHP
php中数组最简单的使用方法
2020/12/27 PHP
javascript生成/解析dom的CDATA类型的字段的代码
2007/04/22 Javascript
Jquery submit()无法提交问题
2013/04/21 Javascript
javascript完美拖拽的实现方法
2013/09/29 Javascript
深入理解JavaScript系列(29):设计模式之装饰者模式详解
2015/03/03 Javascript
使用JQuery实现Ctrl+Enter提交表单的方法
2015/10/22 Javascript
jquery利用拖拽方式在图片上添加热链接
2015/11/24 Javascript
js通过指定下标或指定元素进行删除数组的实例
2017/01/12 Javascript
ES6学习之变量的解构赋值
2017/02/12 Javascript
AngularJS监听路由变化的方法
2017/03/07 Javascript
Angular 2父子组件数据传递之局部变量获取子组件其他成员
2017/07/04 Javascript
Js利用Canvas实现图片压缩功能
2017/09/13 Javascript
详解从零搭建 vue2 vue-router2 webpack3 工程
2017/11/22 Javascript
react-native-video实现视频全屏播放的方法
2018/03/19 Javascript
Vue三层嵌套路由的示例代码
2018/05/05 Javascript
浅谈Vue SSR中的Bundle的具有使用
2019/11/21 Javascript
Vue的data、computed、watch源码浅谈
2020/04/04 Javascript
[07:54]DOTA2-DPC中国联赛 正赛 iG vs VG 选手采访
2021/03/11 DOTA
Python3处理HTTP请求的实例
2018/05/10 Python
django 删除数据库表后重新同步的方法
2018/05/27 Python
djang常用查询SQL语句的使用代码
2019/02/15 Python
pycharm 2019 最新激活方式(pycharm破解、激活)
2020/09/22 Python
Python中私有属性的定义方式
2020/03/05 Python
基于HTML5超酷摄像头(HTML5 webcam)拍照功能实现代码
2012/12/13 HTML / CSS
Ryderwear澳洲官网:澳大利亚高端健身训练装备品牌
2018/09/18 全球购物
Saks Fifth Avenue澳洲/亚太地区:萨克斯第五大道精品百货店
2019/06/09 全球购物
俄罗斯香水和化妆品网上商店:NOTINO.ru
2019/12/17 全球购物
shell的种类有哪些
2015/04/15 面试题
机械专业毕业生自荐信
2013/11/02 职场文书
会计实习生自我鉴定
2013/12/12 职场文书
迎新晚会主持词开场白
2015/05/28 职场文书
小学教代会开幕词
2016/03/04 职场文书
Android 界面一键变灰 深色主题工具类
2022/04/28 Java/Android