PHP搭建自己的web框架-視圖/模板引擎

分類:編程 時間:2016-11-04
[摘要: 視圖,MVC中的V,View,若何將數據經過適合的格式揭示給用戶或挪用圓。 固然應用甚麽格式揭示由操縱器間接操縱,但基礎緣由由人或體系決意]

        視圖,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 = http://www.ithao123.cn/get_object_vars ( $obj );
foreach ( $data as $key => $value ) {
$this->Assign ( $key, $value );
}
}

這樣只要是類的public屬性,即可傳遞給模板,而不用一個一個assign。


<?php
require_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=http://www.ithao123.cn/"' . URL_CSS . $css_path . '?v=' . UPDATE_TIME . '" rel="stylesheet" type="text/css"/>';
	}
	protected function addMoreJs($js_path) {
		$this->more_js .= '';
	}
	protected function addMoreFooterJs($js_path) {
		$this->more_footer_js .= '';
	}
}


main_frame.html:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>{$page_title}</title>
        <link href=http://www.ithao123.cn/"__CSSPATH__common.css?v=<?php echo UPDATE_TIME;?>" media="all" rel="stylesheet" type="text/css">
		{$more_css}
		{$more_js}
    
    
        <?php include ('common/header.html');?>
        
<?php if($page_tpl){ ?> <?php include ($page_tpl);?> <?php }?>
<?php include ('common/footer.html');?> {$more_footer_js}

控制器使用時:

<?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


Tags: require 控制器 java 開發 如何

文章來源:


ads
ads

相關文章
ads

相關文章

ad