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&amp;mysql(五)
Oct 09 PHP
构建简单的Webmail系统
Oct 09 PHP
使用数据库保存session的方法
Oct 09 PHP
了解Joomla 这款来自国外的php网站管理系统
Mar 11 PHP
全新的PDO数据库操作类php版(仅适用Mysql)
Jul 22 PHP
解析yahoo邮件用phpmailer发送的实例
Jun 24 PHP
封装ThinkPHP的一个文件上传方法实例
Oct 31 PHP
php实现XML和数组的相互转化功能示例
Feb 08 PHP
PHP解耦的三重境界(浅谈服务容器)
Mar 13 PHP
PHP rmdir()函数的用法总结
Jul 02 PHP
laravel多条件查询方法(and,or嵌套查询)
Oct 09 PHP
使用laravel指定日志文件记录任意日志
Oct 17 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
swfupload 多文件上传实现代码
2008/08/27 PHP
PHP 截取字符串专题集合
2010/08/19 PHP
php超快高效率统计大文件行数
2015/07/05 PHP
利用Homestead快速运行一个Laravel项目的方法详解
2017/11/14 PHP
php swoft框架实例用法
2020/12/22 PHP
jquery鼠标停止移动事件
2013/12/21 Javascript
jQuery实现带玻璃流光质感的手风琴特效
2015/11/20 Javascript
基于canvas实现的钟摆效果完整实例
2016/01/26 Javascript
JavaScript判断图片是否已经加载完毕的方法汇总
2016/02/05 Javascript
js计算时间差代码【包括计算,天,时,分,秒】
2016/04/26 Javascript
yarn与npm的命令行小结
2016/10/20 Javascript
vue双向数据绑定原理探究(附demo)
2017/01/17 Javascript
IntersectionObserver实现图片懒加载的示例
2017/09/29 Javascript
JS实现合并json对象的方法
2017/10/10 Javascript
详解nodejs 开发企业微信第三方应用入门教程
2019/03/12 NodeJs
layui富文本编辑器前端无法取值的解决方法
2019/09/18 Javascript
Python的Flask框架与数据库连接的教程
2015/04/20 Python
Python的Django框架中消息通知的计数器实现教程
2016/06/13 Python
Python可变参数用法实例分析
2017/04/02 Python
[原创]windows下Anaconda的安装与配置正解(Anaconda入门教程)
2018/04/05 Python
浅谈python中频繁的print到底能浪费多长时间
2020/02/21 Python
pycharm通过anaconda安装pyqt5的教程
2020/03/24 Python
python 下载文件的几种方法汇总
2021/01/06 Python
欧洲最大的球衣网上商店:Kitbag
2017/11/11 全球购物
NBA德国官方网上商店:NBA Store德国
2018/04/13 全球购物
校领导推荐信
2013/11/01 职场文书
大学运动会入场词
2014/02/22 职场文书
学校元旦晚会开场白
2014/12/14 职场文书
贫困生助学金感谢信
2015/01/21 职场文书
见习期个人总结
2015/03/05 职场文书
2015年保安个人工作总结
2015/04/02 职场文书
酒桌上的开场白
2015/06/01 职场文书
山楂树之恋观后感
2015/06/11 职场文书
遇事可以测出您的见识与格局
2019/09/16 职场文书
golang中的struct操作
2021/11/11 Golang
彻底弄懂Python中的回调函数(callback)
2022/06/25 Python