PHP沉思錄-第三篇-Smarty-左輕侯-《程序員》2007年10月號

建立時間:2007-10-31 21:23:11   最後修改時間:2007-10-31 21:23:11  
php

PHP沉思錄之三:Smarty 
  左輕侯 
  2007.8.11 
   
   在任何Web應用中,如何將程序代碼和界面設計,或者說,將邏輯層和表現層分離開來,都會是一個問題。對於PHP這種類型的嵌入網頁的腳本語言,這一問題尤爲突出。在新手編寫的代碼中,把訪問數據庫的代碼和操縱HTML元素的代碼寫在同一個頁面裏,是很常見的狀況。爲了不這一問題,開發者傾向於將涉及業務邏輯的代碼封裝在某些單獨的庫文件中,再在負責顯示界面的文件中將它們include進來。可是,這仍然沒法避免在顯示界面的文件中包含大量的PHP代碼。究其因此然,是由於除了涉及業務邏輯的代碼之外,即便僅僅在顯示層,也每每涉及到複雜的顯示邏輯。在一個典型的顯示頁面中,程序須要先包含全部必需的庫文件,初始化上下文環境,建立相關業務邏輯對象(假如數據庫訪問代碼已經被業務邏輯對象封裝,能夠節省數據庫相關的代碼),最後在HTML的空隙中把對象格式化爲HTML元素進行顯示。因而咱們看到了無數這樣的頁面,在第一行HTML開始以前,就已經包含了數十行甚至更多的PHP代碼,在HTML的內部,仍然充滿了各類各樣的PHP代碼。所以,PHP代碼和HTML代碼攪和在一塊的問題仍然沒法解決,對HTML的修改仍然可能致使整個PHP程序崩潰。更加麻煩的是,這種不清晰的結構妨礙了PHP應用在規模上的進一步擴張。 
   爲了解決這一問題,模板(template)技術應運而生。模板技術的基本原理是,經過一個解析器(parser),讀取指定的模板文件(包含了某些特定標籤的HTML文件),將這些標籤替換爲相關的PHP變量,再輸出爲標準的HTML。經過這種方式,不但分離了業務邏輯層和表現層,並且也儘量地分離了顯示邏輯和HTML代碼。經過替換不一樣的模板文件,能夠方便地生成各類格式的輸出,例如HTML,XML,WML,後期稍加處理甚至能夠生成PDF和Flash。早期較爲著名的PHP模板引擎有PHPLib中的Template和FastTemplate。 
   可是,模板技術也有其先天的缺陷。 
   
   沒法完全分離邏輯。顯示邏輯和HTML代碼很難經過簡單的標籤替換,實現完全的分離。例如,遍歷並顯示一個數組,在PHP中能夠用簡單的foreach語句實現,可是使用模板時,就須要進行對整個模板文件進行屢次替換操做,形成效率的極大下降;或者根據不一樣的數據值顯示不一樣的格式,若是模板文件徹底不包含PHP代碼,那麼將很難作到這一點。 
   解析致使的性能損失。因爲每次PHP頁面被訪問時,解析器都必須對模板文件進行替換操做,無疑會下降PHP應用的性能。尤爲在屢次的替換操做時更是如此。所以,不使用模板比使用模板每每更加快速,這也是許多PHP程序員摒棄模板技術的緣由之一。 
   
  在通過數年的發展以後,「編譯型」的模板技術漸漸佔據了主流。所謂「編譯型」,是指解析器讀取模板文件之後,並不直接生成靜態HTML,而是「編譯」成一個新的PHP文件,並將它保存起來。之後訪問該頁面時,模板引擎會直接執行「編譯」後的PHP文件。Smarty是這種模板引擎的表明。 
   針對以上的兩個問題,Smarty做了以下處理: 
   
   獨立語法。Smarty實現了一套本身的語法,這套語法不但支持變量替換和簡單的判斷,並且支持循環,修飾符(modifier),內置了不少功能強大的函數,並且還支持自定義函數。這套系統保證Smarty可以徹底獨立地處理顯示輸出,無須再和PHP有什麼瓜葛。事實上,在Smarty模板中,是不能夠直接使用PHP代碼的(經過顯式定義可使用),這也是一種強制分離邏輯層和表現層的方式。(理論上來講,Smarty的模板文件也能夠應用於其它語言。)可是,這種解決方式也受到了指責,由於Smarty的語法過於強大,幾乎變成了一門新的語言,指責者認爲,這反而增長了複雜性。可是,根據做者的實際經驗,Smarty的語法不但很是簡單直觀,並且只須要掌握一些最初級的語法,就足能夠應付絕大多數的應用。即便是不懂編程的網頁設計師,也很容易就可以掌握。 
   編譯機制。Smarty的「編譯」機制,節省了用於反覆解析模板文件的時間,極大地提升了速度。因爲「編譯」後生成的是標準的PHP文件,所以從理論上來講,執行的速度不會低於沒有模板的PHP應用的速度。在一些和解析型模板引擎進行的對比測試中,Smarty在第一次訪問時落後,可是在之後的訪問中速度遠遠超出競爭對手。並且,這種編譯過程是智能的,在模板文件的內容被改變後,Smarty會自動從新編譯,所以對於開發者來講,編譯過程徹底無需人工干預。另外,若是你願意的話,生成的PHP文件還能夠方便地應用於Zend Accelerator這樣的工具,進行二次編譯。 
   
  除此以外,Smarty還擁有其餘一些優秀的特性: 
   
   緩存機制。因爲實現了編譯機制,在接收到對某個模板文件的訪問請求時,Smarty會自動將它重定向到編譯後的PHP文件。可是,這也意味着,Smarty也能夠將它重定向到任何其餘的文件——例如靜態的HTML文件。在此基礎之上,Smarty實現了本身的基於頁面的緩存機制。Smarty可以將編譯後的PHP文件產生的結果——靜態HTML——保存起來,將重複發送的請求直接重定向給它,這意味着對於第一次以後的請求,不須要執行任何PHP代碼(Smarty自己的代碼固然除外)。對於不須要頻繁更新的頁面(咱們知道這種網頁每每在整個網站中佔大多數),經過這種緩存機制獲取的性能提高是驚人的。並且,因爲它是在頁面級實現的,所以徹底無須涉及到複雜的對象級緩存問題,保持了邏輯上的簡單性。 
   可配置性。Smarty在開發之初就將高度的可配置性做爲本身的一個設計目標。它自己以100%的PHP編寫,以源代碼的方式發行,只須要將Smarty簡單地拷貝到你的文件路徑中,就可使用了。Smarty的各項配置變量,均可以經過修改config文件或者手動編碼進行定製。例如,Smarty默認的定界符是花括號({}),可是這每每和Javascript以及CSS中的花括號衝突。爲了解決這一問題,能夠簡單地將默認定界符修改成其餘的字符(例如ASP風格的「<%」和「%>」)。 
   可擴展性。Smart的實現基於面向對象的架構,而且提供了插件機制,很是便於用戶修改和擴展其默認的認爲。固然,你也能夠直接修改它的源代碼來達到目的。(對於基於腳本語言的開源應用來講,這是很是愜意的,由於你甚至不須要從新編譯。) 
   
  讓咱們來看一個最簡單的Smarty應用。這個應用包括兩個文件: 
   
  TestSmarty.php 調用Smarty類庫,初始化變量,並解析相應的模板文件 
  TestSmarty.tpl 模板文件,其實就是包含了Smarty標籤的HTML,放在指定的模板目錄下,默認是./templates 
   
   TestSmarty.php的內容以下: 
   
  <?php 
  include_once("./smarty/Smarty.class.php"); 
   
  $Smarty = new Smarty(); 
  $Smarty->assign("HelloStr", "Hello, world"); 
  $Smarty->display("TestSmarty.tpl"); 
  ?> 
   
   這個文件的內容很是簡單,任何有過PHP經驗的程序員都應該可以理解:首先將Smarty類庫所在的文件include進來,而後建立一個新的Smarty對象,並對HelloStr變量進行賦值,最後解析TestSmarty.tpl文件。 
   TestSmarty.php的內容以下: 
   
  This is a string from Smarty: {$HelloStr} 
   
   解析的結果爲: 
   
  This is a string from Smarty: Hello, world 
   
   此時檢查存放編譯後的PHP文件的子目錄(默認是./templates_c),能夠找到一個名叫%%65^650^65099D8B%%TestSmarty.tpl.php的文件,內容以下: 
   
  <?php /* Smarty version 2.6.18, created on 2007-08-12 03:04:56 
   compiled from TestSmarty.tpl */ ?> 
  This is a string from Smarty: <?php echo $this->_tpl_vars['HelloStr']; ?> 
   
   這就是Smarty引擎編譯生成的結果。 
   爲了啓用緩存,能夠在TestSmarty.php文件中加入這麼一行(固然必須在display方法以前): 
   
  $Smarty->caching = 1; 
   
   從新訪問該頁面,而後檢查存放緩存文件的子目錄(默認是./cache),能夠找到一個名叫%%65^650^65099D8B%%TestSmarty.tpl的文件,內容以下: 
   
  136 
  a:4:{s:8:"template";a:1:{s:14:"TestSmarty.tpl";b:1;}s:9:"timestamp";i:1186888266;s:7:"expires";i:1186891866;s:13:"cache_serials";a:0:{}}This is a string from Smarty: Hello, world 
   
   這就是生成的緩存文件,在靜態的HTML文件以前,包含了已經序列化的PHP信息。雖然這些信息沒法被直接閱讀,可是多少仍是可以猜想出來:模板的子目錄,模板文件名,時間戳,生存期(過時時間),等等。若是讀者有興趣研究它們的詳細定義,能夠閱讀Smarty的源代碼。 
   注意,上述信息中包含了一項:生存期,即當前緩存在多長時間之後過時。Smarty默認的生存期是1小時,即3600秒。能夠經過修改Smarty屬性來設置生命期,代碼以下: 
   
  $Smarty->cache_lifetime = 1800; 
   
   時間單位是秒,設置爲1800表示當前緩存半小時後過時。 
   Smarty還支持爲同一個模板建立多個緩存實例,這在實際應用中是很是常見的。舉例來講,假設某個博客系統中,顯示article的頁面爲Article.php,對應的模板文件爲Article.tpl。可是,article頁面的內容根據不一樣的article ID而不一樣,所以,必須爲同一個頁面建立不一樣的緩存實例。Smarty能夠輕鬆作到這一點: 
   
  $Smarty->display("Article.tpl", $ArticleId); 
   
   只要將一個惟一標識符(在這個例子中是article的ID)做爲第二個參數傳給display方法,Smarty就會自動完成一切。 
   
   Smarty出現的時間雖然較老牌的PHPLib Template和FastTemplate爲晚,可是發展很是迅速,並且已經成爲PHP的官方子項目,擁有二級域名http://smarty.php.net/。正如它的官方站點上所說,與其說Smarty是一個模板引擎,不如說它是一個表現層的Framework。這句話極爲重要。
   做者我的認爲,Smarty誕生和逐漸取得主流地位的意義,不只僅是提供了一個優秀的模板引擎,而是表示PHP在解決更大規模的應用上邁出了堅實的一步。若是說Java是一開始就將解決大規模應用做爲本身的設計目標的話,那麼PHP就是在開源社區的推進下,在不斷的改進中逐漸接近這一目標。當一個PHP應用採用了Smarty這樣優秀和成熟的表現層解決方案,以及其餘一些相似的技術(例如好的ORM解決方案)之後,它可以解決的問題的規模就比過去大得多了。經過這些現象,咱們能夠看到,PHP,或者說LAMP,正在以穩健而持續的步伐,向企業級應用邁進。 程序員

相關文章
相關標籤/搜索