我(wǒ)(wǒ)常用的一(yī)個非常好的生(shēng)成靜态頁面的模闆處理類Template_class

發布時間:2008年03月04日      浏覽次數:3678 次
<?php
//呵呵,我(wǒ)(wǒ)的英文不是很好,下(xià)面很多注釋不一(yī)定正确,懂英文的就自已看英文注釋吧,也許更容易看懂
class Template_class
{
      /**
       * When is set to true it makes the class clean the loops and cloops data
       * The value of this variable can be set while creating the object 當創建對象的時候,這個變量的值可以被設置
       *
       * @var bool
       * @access public
       */
      var $reset = TRUE;
      /**
       * The beginning of the normal tags
       *
       * @var string
       * @access public
       */
      var $ldelim = '{'; //正規标簽始端
      
      /**
       * The end of the normal tags
       *
       * @var string
       * @access public
       */
      var $rdelim = '}';//正規标簽末端
      /**
       * The beginning of the opening tag for blocks
       *
       * @var string
       * @access public
       */
      var $BAldelim = '{';//開(kāi)始标簽始端
      /**
       * The end of the opening tag for blocks
       *
       * @var string
       * @access public
       */
      var $BArdelim = '}';//開(kāi)始标簽末端
      /**
       * The beginning of the closing tag for blocks
       *
       * @var string
       * @access public
       */
      var $EAldelim = '{/';//結束标簽始端
      /**
       * The end of the closing tag for blocks
       *
       * @var string
       * @access public
       */
      var $EArdelim = '}'; //結束标簽末端
      /**
       * Array containing the data for the tag: tags
       *
       * @var array
       * @access private
       */
      var $_scalars = array();//tag:标簽 數組
      /**
       * Array containing the data for the loop: tags
       *
       * @var array
       * @access private
       */
      var $_arrays = array();//loop:标簽 數組
      /**
       * Array containing the information about which array tags
       * should be enabled for if: tags and which elements should be used
       * since trying to find ifs for each array element and
       * for each array entry would take a lot of time.
       *
       * @var array
       * @access private
       */
      var $_arrays_ifs = array();
      /**
       * Array containing the data for the cloop: tags
       *
       * @var array
       * @access private
       */
      var $_carrays = array();//cloop:标簽 數組
      /**
       * Array containing the data for the if: tags
       *
       * @var array
       * @access private
       */
      var $_ifs = array();//if:标簽 數組
      /**
       * Array containing the information of the plugins to be loaded
       *
       * @var array
       * @access private
       * @see $this->add_plugin
       */
      var $_plugins = array();
      /**
       * Object constructor, set $reset to reset the arrays after processing 對象構造,設置$reset變量在處理後重新初始化數組
       *
       * @access public
       * @param bool $reset
       * @return Template_class
       */
      function Template_class($reset = TRUE)
      {
            $this->reset = $reset;
      }
      /**
       * Set a tag with a value, $var can be a string or an array 設置一(yī)個标簽和一(yī)個值,$var變量可以是一(yī)個字符串或者一(yī)個數組
       * Set $if to true if you want to be able to use that tag with if: conditions
       *
       * @param string $tag
       * @param mixed $var
       * @param bool $if
       */
      function set($tag, $var, $if = NULL)
      {
            if(is_array($var))
            {
                  $this->_arrays[$tag] = $var;
                  if($if!==null)
                  {
                        if(!is_array($if))
                        {
                              $result = $var ? TRUE : FALSE;
                              $this->_ifs[] = $tag;
                              $this->_scalars[$tag] = $result;
                        }
                        else
                        {
                              $result = $var ? TRUE : FALSE;
                              $this->_ifs[] = $tag;
                              $this->_scalars[$tag] = $result;
                              $this->_arrays_ifs[$tag]=$if;
                        }
                  }
            }
            else
            {
                  $this->_scalars[$tag] = $var;
                  if($if) $this->_ifs[] = $tag;
            }
      }
      /**
       * Sets a case loop
       *
       * @access public
       * @param string $tag The tag name
       * @param array $array The array containing the data
       * @param array $cases The array telling about the cases that it should check for
       */
      function set_cloop($tag, $array, $cases)
      {
            $this->_carrays[$tag] = array(
            'array' => $array,
            'cases' => $cases);
      }
      /**
       * Reset the template variables 重設模闆變量
       *
       * @access public
       * @param bool $scalars If the scalars data should be cleaned
       * @param bool $arrays If the arrays data should be cleaned
       * @param bool $arrays_ifs If the arrays_ifs data should be cleaned
       * @param bool $carrays If the case arrays data should be cleaned
       * @param bool $ifs If the ifs data should be cleaned
       * @param bool $plugins If the plugins data should be cleaned
       */
      function reset($scalars=false, $arrays=false, $arrays_ifs=false, $carrays=false, $ifs=false,$plugins=false)
      {
            if($scalars) $this->_scalars = array();
            if($arrays) $this->_arrays = array();
            if($arrays_ifs) $this->_arrays_ifs = array();
            if($carrays) $this->_carrays = array();
            if($ifs) $this->_ifs = array();
            if($plugins) $this->_plugins = array();
      }
      /**
       * Formats the tags & returns a two-element array, 格式化标簽并且返回一(yī)個兩個元素的數組
       * the opening and closing tags 開(kāi)始與結束标簽
       *
       * @access public
       * @param string $tag The tag name
       * @param string $directive The directive name
       * @return array
       */
      function get_tags($tag, $directive)
      {
            $tags['b'] = $this->BAldelim . $directive . ':' . $tag . $this->BArdelim; //如{
            $tags['e'] = $this->EAldelim . $directive . ':' . $tag . $this->EArdelim;
            return $tags;
      }
      /**
       * Formats a simple tag
       *
       * @access public
       * @param string $tag The tag name
       * @param string $directive The tag directive
       * @return string The formated tag
       */
      function get_tag($tag,$directive='tag')
      {
            return $this->ldelim . $directive . ':' . $tag . $this->rdelim;
      }
      /**
       * Extracts a portion of a template( or a string) according to the
       * opening ($tags['b']) and closing ($tags['e']) tags
       *
       * @param array $tags The opening and closing tags/delimeters
       * @param string $contents The content from where it is going to extract
       * @return string The extracted content
       */
      function get_statement($tags, $contents)
      {
            // Locate the statement
            $tag_length = strlen($tags['b']);
            $fpos = $tags['b']===null? 0 : strpos($contents, $tags['b']);
            $lpos = $tags['e']===null? strlen($contents) : strpos($contents, $tags['e']);
            if($fpos===false||$lpos===false)
            return false;
            $fpos += $tag_length;
            $length = $lpos - $fpos;
            // Extract & return the statement
            return substr($contents, $fpos, $length);
      }
      /**
       * Parse the template with the variables 解析模闆變量
       *
       * @access public
       * @param string $contents The template
       * @return string The parsed template
       */
      function parse($contents)
      {
            /**
             * Process the ifs (if any)
             */
            foreach($this->_ifs as $value)
            {
                  $contents = $this->_parse_if($value, $contents);
            }
            /**
             * Process the scalars (if any)
            */
            foreach($this->_scalars as $key => $value)
            {
                  $contents = str_replace($this->get_tag($key), $value, $contents);
            }
            /**
             * Process the arrays (if any)
             */
            foreach($this->_arrays as $key => $array)
            {
                  $contents = $this->_parse_loop($key, $array, $contents);
            }
            /**
             * Process the case arrays (if any)
             */
            foreach($this->_carrays as $key => $array)
            {
                  $contents = $this->_parse_cloop($key, $array, $contents);
            }
            $plugins_count=count($this->_plugins);
            /**
             * Process the plugins (if any)
             */
            for ($n=0;$n<$plugins_count;$n++)
            {
                  if($this->_plugins[$n]['object']===null)
                  $obj=new $this->_plugins[$n]['function']();
                  else
                  $obj=&$this->_plugins[$n]['object'];
                  //
                  //Now we check what protocol version the plugin was designed for
                  //
                  switch ($obj->version('protocol'))
                  {
                        case "1.0":
                              {
                                    //
                                    //Now we give the object itself to the function, so it can access the current settings
                                    //
                                    $contents=$obj->parse($contents,$this);
                              }break;
                  }
            }
            /**
             * Reset the data according to the settings
             */
            if($this->reset) $this->reset(FALSE, TRUE, TRUE, TRUE);
            return $contents;
      }
      /**
       * Parses an if statement //解析一(yī)個if...esle...語句,示例:{if:标簽}...{else:标簽}...{/if:标簽}
       *
       * @access private
       * @param string $tag The tag name
       * @param string $contents The current as-processed template
       * @param string $replace If the function should consider as $replace without checking the real value
       * @return string The parsed template
       */
      function _parse_if($tag, $contents, $replace=null)
      {
            //
            // Get the tags
            //
            $t = $this->get_tags($tag, 'if'); //返回一(yī)個$t數組,值分(fēn)别爲:$t['b']="{if:标簽$tag}",$t['e']="{/if:标簽$tag}",如:{if:test}{/if:test}
            //
            //We loop this so we can process all the ifs for this tag
            //
            while (($entire_statement = $this->get_statement($t, $contents))!==false)
            {
                  // Get the else tag 獲取else标簽
                  $tags['b'] = NULL;
                  $tags['e'] = $this->get_tag($tag, 'else');
                  // See if there's an else statement 判斷是否有else語句
                  if(($else = strpos($entire_statement, $tags['e'])))
                  {
                        // Get the if statement
                        $if = $this->get_statement($tags, $entire_statement);
                        // Get the else statement
                        $else = substr($entire_statement, $else + strlen($tags['e']));
                  }
                  else
                  {
                        $else = NULL;
                        $if = $entire_statement;
                  }
                  //
                  //If the function wasn't called with a value for $replace we check the _scalars array
                  //
                  if($replace===null||!is_bool($replace))
                  $replace=!empty($this->_scalars[$tag])?true:false;
                  //
                  //If the condition is valid then we use the 'if' (first) part, if not, then we use 'else'
                  //
                  $replace=($replace) ? $if : $else;
                  //
                  // Parse the template
                  //
                  $contents = str_replace($t['b'] . $entire_statement . $t['e'], $replace, $contents);
            }
            //
            //Return the template
            //
            return $contents;
      }
      /**
       * Parses a loop //解析一(yī)個loop語句,示例:{loop:标簽}...{/loop:标簽}
       *
       * @access private
       * @param string $tag Tag name
       * @param array $array The array containing the loop data
       * @param string $contents The current as-processed template
       * @return string The parsed template
       */
      function _parse_loop($tag, $array, $contents)
      {
            // Get the tags & loop
            $t = $this->get_tags($tag, 'loop');
            while (($loop = $this->get_statement($t, $contents))!==false)
            {
                  $parsed = NULL;
                  $if_key_exists=isset($this->_arrays_ifs[$tag]);
                  // Process the loop
                  foreach($array as $key => $value)
                  {
                        /**
                         * We create a copy of the loop so we can keep the original loop
                         * but work on this one
                         */
                        $i = $loop;
                        if($if_key_exists&&isset($this->_arrays_ifs[$tag][$key]))
                        $i=$this->_parse_if($tag . '.' . $key,$i,!empty($value)?true:false);
                        /**
                         * array(1=>array('key_name'=>'value','some_key'=>'value'))
                         * {tag:tag_name[].key_name},{tag:tag_name[].some_key}
                         * {tag:tag_name[].key_name[]},{tag:tag_name[].some_key[].some_subkey}
                         */
                        if(is_numeric($key) && is_array($value))
                        {
                              foreach($value as $key2 => $value2)
                              {
                                    if($if_key_exists&&isset($this->_arrays_ifs[$tag][$key2]))
                                    $i=$this->_parse_if($tag . '[].' . $key2,$i,!empty($value2)?true:false);
                                    if(!is_array($value2))
                                    {
                                          // Replace associative array tags
                                          $i = str_replace($this->get_tag($tag . '[].' . $key2), $value2, $i);
                                    }
                                    else
                                    {
                                          // Check to see if it's a nested loop
                                          $i = $this->_parse_loop($tag . '[].' . $key2, $value2, $i);
                                    }
                              }
                        }
                        /**
                         * array('tsgsgs'=>'sgsgdgg')
                         * {tag:tag_name.key_name}
                         */
                        elseif(is_string($key) && !is_array($value))
                        {
                              $i = str_replace($this->get_tag($tag . '.' . $key), $value, $i);
                        }
                        /**
                         * array(1=>'fff')
                         * {tag:tag_name[]}
                         */
                        elseif(!is_array($value))
                        {
                              $i = str_replace($this->get_tag($tag . '[]'), $value, $i);
                        }
                        // Add the parsed iteration
                        if(isset($i)) $parsed .= rtrim($i);
                  }
                  //
                  // Parse the template
                  //
                  $contents=str_replace($t['b'] . $loop . $t['e'], $parsed, $contents);
            }
            //
            //Return the template
            //
            return $contents;
      }
      /**
       * Parse a case loop 解析一(yī)個case循環語句,相當于switch一(yī)樣
       *
       * @access private
       * @param string $tag The tag name that is going to be parsed
       * @param array $array Array with the loop elements
       * @param string $contents The current as-processed template
       * @return string The parsed template
       */
      function _parse_cloop($tag, $array, $contents)
      {
            // Get the tags & loop
            $t = $this->get_tags($tag, 'cloop'); //返回{cloop:名稱}{case:名稱}...{default:名稱}{/cloop:名稱}
            while (($loop = $this->get_statement($t, $contents))!==false)
            {
                  // Set up the cases
                  $array['cases'][] = 'default';
                  $case_content = array();
                  $parsed = NULL;
                  // Get the case strings
                  foreach($array['cases'] as $case)
                  {
                        $ctags[$case] = $this->get_tags($case, 'case');
                        $case_content[$case] = $this->get_statement($ctags[$case], $loop);
                  }
                  // Process the loop
                  foreach($array['array'] as $key => $value)
                  {
                        if(is_numeric($key) && is_array($value))
                        {
                              // Set up the cases
                              if(isset($value['case'])) $current_case = $value['case'];
                              else $current_case = 'default';
                              unset($value['case']);
                              $i = $case_content[$current_case];
                              // Loop through each value
                              foreach($value as $key2 => $value2) {
                                    $i = str_replace($this->get_tag($tag . '[].' . $key2), $value2, $i);
                              }
                        }
                        // Add the parsed iteration
                        $parsed .= rtrim($i);
                  }
                  // Parse & return the final loop
                  $contents=str_replace($t['b'] . $loop . $t['e'], $parsed, $contents);
            }
            return $contents;
      }
      /**
       * Parses the file $file_name as a template
       *
       * @access public
       * @param string $file The template file name
       * @return string The processed template
       */
      function fetch($file,$filename = '')
      {
            // Open the file
            $fp = fopen($file, 'rb');
            if(!$fp) return FALSE;
            // Read the file
            $contents = fread($fp, filesize($file));
            // Close the file
            fclose($fp);
            // Parse and return the contents
            
            if (empty($filename)){
            
                  /*------------------------------------*/
                  //動态浏覽
                  return $this->parse($contents);
                  /*------------------------------------*/
            
            }else{
            
                  /*------------------------------------*/
                  //生(shēng)成靜态頁面
                  $content = $this->parse($contents);
                  
                  $handle = fopen ($filename,"w"); //打開(kāi)文件指針,創建文件
                  /*
                   檢查文件是否被創建且可寫
                  */
                  if (!is_writable ($filename)){
                  //die ("文件:".$filename."不可寫,請檢查其屬性後重試!");
                  }
                  if (!fwrite ($handle,$content)){ //将信息寫入文件
                  //die ("生(shēng)成文件".$filename."失敗!");
                  }
                  fclose ($handle); //關閉指針
                  /*------------------------------------*/
            
            }
      }
      /**
       * Works the same way as set() excepting that if the tag already exists //除了if标簽已經存在以外(wài),功能與set()一(yī)樣
       * it doesn't replaces it, it appends the new value (if it is an string)
       * or it merges the content (if it is an array). //append()不能代替set(),append() 添加一(yī)個新值(如果這個值是一(yī)個字符串),或者添加一(yī)個元素(如果它是一(yī)個數組)
       * Please note that this function will not make any change
       * to the array_ifs data, to update that information,//請注意這個函數對array_ifs數據更新信息不會産生(shēng)任何改變
       * set() has to be used instead //set()函數則一(yī)定會替換舊(jiù)的值
       *
       * @param string $tag
       * @param mixed $var
       * @param bool $if
       */
      function append($tag, $var, $if = NULL)
      {
            if(is_array($var))
            {
                  if(!isset($this->_arrays[$tag]))
                  $this->_arrays[$tag]= $var;
                  else
                  $this->_arrays[$tag]=array_merge($this->_arrays[$tag],$var);
                  if($if)
                  {
                        $result = $var ? TRUE : FALSE;
                        $this->_ifs[] = $tag;
                        $this->_scalars[$tag] = $result;
                  }
            }
            else
            {
                  if(!isset($this->_scalars[$tag]))
                  $this->_scalars[$tag] = $var;
                  else
                  $this->_scalars[$tag] .= $var;
                  if($if) $this->_ifs[] = $tag;
            }
      }
      /**
       * Adds a plugin to be called when a template is being parsed
       * The $plugin_name is the name of the class which is the plugin
       *
       * The $setup var may contain any type of data, because it is pased directly to the $plugin_name::setup() function of the plugin class
       * The arguments passed to the $plugin_name::parse() function will be $contents and the object itself ($this), in that order, and the function will only return the parsed template.
       *
       * The $plugin_name::setup() function may return an array with some settings
       *
       * Notes:
       *       The plugin class must have the next functions, which are going to be called by the template engine:
       *             -$plugin_name::setup() This function can be used to setup either the template engine when calling the plugin or to setup the plugin itself, in the last case, the $setup param can be used to give some settings to the plugin
       *             -$plugin_name::parse() This function is called when the class 'executes' the plugin
       *             -$plugin_name::version() This function must have one argument, which specifies the version of what is being requested: 'protocol' is the current plugins protocol, for the current version is 1.0; 'plugin' is the plugin version, it can be useful to debug
       *
       * @access public
       * @param string $plugin_name The name of the function or class to be called
       * @param mixed $setup Special settings that can be given to the plugin
       */
      function add_plugin($plugin_name,$setup=null)
      {
            $n=count($this->_plugins);
            $this->_plugins[$n]['function']=$plugin_name;
            $this->_plugins[$n]['setup']=$setup;
            $obj=new $plugin_name();
            $this->_plugins[$n]=array_merge($this->_plugins[$n],$obj->setup($setup));
            if (!isset($this->_plugins[$n]['refresh_object'])||$this->_plugins[$n]['refresh_object']===false)
            $this->_plugins[$n]['object']=&$obj;
            else
            $this->_plugins[$n]['object']=null;
      }
}
?>
=================================
示例
=================================
将以上代碼保存到Template_class.php文件中(zhōng).看不看得懂并不重要,隻要看懂以下(xià)代碼學會用就可以了,以下(xià)主要的代碼我(wǒ)(wǒ)都加在後面******号,其它的代碼可有可無,自已寫就得了,靈活運用
--------------------------------
調用類的測試頁 test.php 相關代碼
--------------------------------
<?php
include ("conn.php");//創建數據庫鏈接
include ("mysql_func.php");//自定義的一(yī)個數據庫處理頁面
require_once("Template_class.php");//******這是上面的模闆處理類頁面
$tpl=new Template_class();//******創建對象
$sql = "select * from test ";
genpage($sql,15);//這是一(yī)個分(fēn)頁函數,具體(tǐ)代碼在mysql_func.php裏,統計總頁數,并返回一(yī)個$sql語句,以便下(xià)面這行使用,15爲每頁顯示的記錄數
$result = mysql_query($sql);
while($rs =mysql_fetch_array($result))
{
      $test[] = array("str"=>"$rs[str]");//******這個數組的名稱很重要,也可以自定義,但要與下(xià)面set裏的參數$test名稱相同,最好三個參數的名稱都一(yī)樣,如下(xià)面的test,如果頁面裏不用顯示數據列表的話(huà),此數組可省略,str爲數據庫表裏的一(yī)個字段名稱
//上面這裏隻以顯示一(yī)個字段爲例,如果有多個字段則$test[] = array("str"=>"$rs[str]","字段名稱"=>"值",...);
}
//******以下(xià)set()函數比較重要,主要是将模闆面裏的相關标簽替換爲相關值,$tpl->set("标簽名稱","要替換的值");
$tpl->set("test",$test,array("test"=>true));//将數據替換到靜态模闆頁相關位置,注意後面的array("test"=>true)這個參數,一(yī)般是顯示數據列表時用到
$tpl->set("showpage",showpage());//******将分(fēn)頁代碼插入靜态模闆頁的指定位置
$tpl->set("title","測試調用模闆處理類");//******如果隻是一(yī)個字符串的話(huà),可以這樣子
//...根據模闆頁面設置好的标簽多少在此增加或減少$tpl->set()
die($tpl->fetch("mode.html"));//******将數據填充入靜态模闆頁mode.html并直接顯示出來,不生(shēng)成靜态頁面
//如果需要生(shēng)成靜态頁面的話(huà),那麽上一(yī)句這樣寫即可,die($tpl->fetch("模闆頁的路徑及名稱","要生(shēng)成頁面的路徑及名稱"));如die($tpl->fetch("mode.html","/1/1.html"));
      
?>
--------------------------------
靜态模闆頁 mode.html 相關代碼
--------------------------------
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
</head>
<body>
<table>
<tr><td>{tag:title}<!--這裏就是上面那個tpl->set("title","測試調用模闆處理類");要替換的位置--></td></tr>
<!--下(xià)面開(kāi)始循環顯示記錄,下(xià)面的那個:号左邊的标簽test可以改變,但要對應正确-->
{if:test}
{loop:test}
<tr>
<td align="center">{tag:test[].str}</td>
<!--
如果有更多字段的話(huà)
<td align="center">{tag:test[].str2}</td>
<td align="center">{tag:test[].str3}</td>
...
-->
</tr>
{/loop:test}
{else:test}
<tr>
<td height="100" align="center">沒有數據</td>
</tr>
{/if:test}
</table>
<table width="100%" border="0" cellpadding="0" cellspacing="0">
<tr>
<td>{tag:showpage}<!--這裏是分(fēn)頁處--></td>
</tr>
</table>
</body>
</html>
ok,就說到這了,其它的就自已去(qù)研究與測試吧,呵呵
文章來源:桂林唯創網絡
免責聲明:本站相關技術文章信息部分(fēn)來自網絡,目的主要是傳播更多信息,如果您認爲本站的某些信息侵犯了您的版權,請與我(wǒ)(wǒ)們聯系,我(wǒ)(wǒ)們會即時妥善的處理,謝謝合作!