PHP搭建自己的web框架-视图/模板引擎
来源:互联网 发布:在北京干什么挣钱知乎 编辑:程序博客网 时间:2024/05/17 05:17
视图,MVC中的V,View,如何将数据通过合适的格式展现给用户或调用方。
当然使用什么格式展现由控制器直接控制,但根本原因由人或系统决定。
本文主要描述的是如何在MVC的web框架中输出网页视图,也就是HTML格式的视图。
从开始学习PHP的教程,一般都是直接在PHP中嵌入HTML,这种方式简单粗暴,但也是最根本最高效的方式。
回想一下,上面部分代码是逻辑和数据准备,下面部分是嵌入HTML的PHP代码。
这里不能容忍的不是PHP中嵌入HTML,而是业务逻辑与视图不分离,从代码分离、人员分工等角度来说都不是很好的做法。
MVC的主要思想是层次分明,功能逻辑与视图分离,而是否在视图中使用PHP原生语法,站在MVC角度并不是主要关心的。所以作为MVC中视图的模板引擎,第一要素是分离,其次才是考虑性能与语法。
对PHP有是否使用模板引擎之争,以分离为核心的MVC,并不一定要使用模板引擎,但使用模板引擎能更好地分离,分离得更清晰。
如果以过程式开发,可以在A文件写逻辑,然后最后require B,B写视图文件。这种情况,不强调模板引擎。
而对于面向对象的开发,上述方式显得异样;或者说受java或ruby on rails影响,会抽象出专门的模板引擎来渲染视图。这种情况讲模板引擎才更有意义。
对于一些开源项目或框架的做法,我遇到过的这里简单列举一下。
1. 跟入门教程一样,业务逻辑与视图显示部分混在一起。
2. 把页面元素封装成一个个构件方法。这种方式不把流程看下来,都不知道哪输出了视图,而且布局、定位方面不太容易理解。
3. 通常意义下的视图做法,组合一个模板引擎,初始化模板引擎,assign数据,display显示视图。比如:
$this->view = new View();
$this->view->tpl_dir = PATH_PAGE_VIEW;
$this->view->cache_dir = PATH_PAGE_CACHE;
$this->view->cache_time = TPL_CACHE_TIME;
$view->assign("name","lory");
$view->assign("uid",123456);
$view->display("index.tpl");// or $view->renderHtml('index.tpl);
4. 因为每次assign显示很麻烦,有些做法是把整个控制器对象传给视图,由视图取出public属性。
这种方式挺好,推荐使用。
接下来是两个主题,怎么实现一个模板引擎和怎样使用模板引擎。
如何实现模板引擎
说到模板引擎,smarty对PHP来说是绕不开的,各种方法、功能和机制完备,其中上所有场景有考虑到吧,但实际上在项目中使用时,只使用了其很少的几个特性和功能,同时其性能也不好。因此选择其它模板引擎或自己实现一个,也是有必要的,关键是不难。
看一下smarty的实现,或搜索一下PHP模板引擎,很多相关实现,本文也不详细说明。可以看看tmd_tpl,我们项目就是在tmd_tpl基础上修改了一下。
可以看出,模板引擎编译出来的缓存文件,都是PHP中嵌入HTML的方式,模板引擎只是做了转换的角色,最终执行的是缓存出来的缓存文件。
如果模板引擎自定义了语法,都是将自定义语法通过匹配替换的方式转化为PHP语法的过程,虽然编译过程效率不高,但如果直接加载缓存结果,也不会有多大损耗。
在自己实现时,页面如何接收数据,可以关注方法extract,或是将页面变量替换成一个方法来接收值。
如何使用模板引擎
一般模板引擎都有使用说明,下面是我们项目中的做法,仅为参考。
将模板引擎组合到控制器父类中,而每一个业务控制器作为子类,即可使用模板引擎。
一般情况下,需要对模板引擎做些封装,子类不会直接调用到模板引擎的方法,而是通过父类方法间接调用。
在tmd_tpl基础上,增加了方法:
function assignObj($obj) {
$data = get_object_vars ( $obj );
foreach ( $data as $key => $value ) {
$this->Assign ( $key, $value );
}
}
这样只要是类的public属性,即可传递给模板,而不用一个一个assign。
<?phprequire_once PATH_LIB . 'tmd_tpl.php';/** */class PCAction {protected $view;public $page_title = '模板引擎示例';/** * 网站header/footer部分 */public $header_tpl = 'common/header.html';public $footer_tpl = 'common/footer.html';/** * 网站内容部分 */public $page_tpl;/** * $page_frame里包含了header_tpl/footer_tpl/page_tpl的布局 */public $page_frame = 'common/main_frame.html';public $more_css = '';public $more_js = '';public $more_footer_js;function __construct() {}/** * 设置模板必要的参数。 */function initViewConfig() {$this->view = new tmd_tpl ();$this->view->tpl_dir = PATH_PAGE_VIEW;$this->view->cache_dir = PATH_PAGE_CACHE;$this->view->cache_time = TPL_CACHE_TIME;$this->view->my_rep = array ('~__ROOT__~' => URL_HOST,'~__JSPATH__~' => URL_JS,'~__CSSPATH__~' => URL_CSS,'~__PLUGINPATH__~' => URL_PLUGIN,'~__IMAGEPATH__~' => URL_IMAGE,'~__VERSION__~' => UPDATE_TIME );}/** * PC端WEB页面的显示。 * * @param string $tpl * 如果指定了,只显示tpl模板,没有指定则显示整个框架模板。 */protected function display($tpl = '') {$this->initViewConfig ();$this->view->assignobj ( $this );if ($tpl) {$this->view->display ( $tpl );} else {if (! $this->page_tpl) {$this->page_tpl = 'index.html';}$this->view->display ( $this->page_frame );}exit ();}protected function addMoreCss($css_path) {$this->more_css .= '<link href="' . URL_CSS . $css_path . '?v=' . UPDATE_TIME . '" rel="stylesheet" type="text/css"/>';}protected function addMoreJs($js_path) {$this->more_js .= '<script type="text/javascript" src="' . URL_JS . $js_path . '?v=' . UPDATE_TIME . '"?></script>';}protected function addMoreFooterJs($js_path) {$this->more_footer_js .= '<script type="text/javascript" src="' . URL_JS . $js_path . '?v=' . UPDATE_TIME . '"></script>';}}
<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>{$page_title}</title> <link href="__CSSPATH__common.css?v=<?php echo UPDATE_TIME;?>" media="all" rel="stylesheet" type="text/css">{$more_css}{$more_js} </head> <body atk="{$ajax_token}"> <?php include ('common/header.html');?> <div class="g-bd"> <?php if($page_tpl){ ?> <?php include ($page_tpl);?> <?php }?> </div> <?php include ('common/footer.html');?>{$more_footer_js} </body></html>
控制器使用时:
<?php class main extends PCAction{public function index(){$this->name = 'frogluo';$this->age = 32;$this->uid = 123456;$this->is_admin = 0;$this->page_tpl = 'index.tpl';$this->display();//或//$this->display('index.tpl');}}
对tmd_tpl变量使用自定义语法,采取替换,流程控制使用原生PHP语法,我觉得是比较好的一种实践组合。
tmd_tpl把模板引擎的基本思想都体现出来了,因此学习与改造都比较适合。
同时还改造了将模板中require/include引用其它模板的内容合并到主模板中,具体可见:
https://github.com/frogluo/php/tmd_tpl
- PHP搭建自己的web框架-视图/模板引擎
- PHP搭建自己的web框架-前言
- PHP搭建自己的web框架-总体概述
- PHP搭建自己的web框架-程序初始化
- PHP搭建自己的web框架-路由
- PHP搭建自己的web框架-控制器
- PHP搭建自己的MVC框架8 视图层
- 一个自己写的PHP模板引擎
- 搭建自己的PHP框架
- 如何用PHP来编写自己的模板引擎
- 如何用PHP来编写自己的模板引擎
- ejs的视图模板引擎
- 使用PHP搭建自己的MVC框架
- 使用PHP搭建自己的MVC框架
- 使用PHP搭建自己的MVC框架
- 使用PHP搭建自己的MVC框架
- 使用php搭建自己的MVC框架
- 使用PHP搭建自己的MVC框架
- Xcode : Your session has expired. Please log in
- HDU 1002 A + B Problem II -- java大法好
- Nginx拷贝流量
- readelf --help
- 数据流重定向
- PHP搭建自己的web框架-视图/模板引擎
- PHP实现的mysql数据库操作类
- 使用maven将项目打成jar包
- ListView从入门到中级,android菜鸟级别,
- Missing iOS Distribution signing identity for
- 回溯算法之集装箱问题
- Gradient Boost 算法流程分析
- leetcode——287—— Find the Duplicate Number
- 根据类型,读取zip文件中单个文件的内容