Devam kir basit PHP şablonlar, [kapalı]

0 Cevap php

Background


Yani, last time Ben gibi tepkiler çok aldım, PHP şablonları hakkında sordu:

  • gerekli değildir; PHP kendi başına yeterince iyi bir çiftleşmiş dilidir.
  • tasarımcılar (veya civarında) ile çalışmak için güçlü ve kolay hem de bir çiftleşmiş dili geliştirmek zor.
  • Zaten, kullanım çiftleşmiş çerçeve X. yapildi
  • sen aptalsın.

Bu noktaların hepsi geçerlilik miktar var. Bunları akılda tutarak, ben çiftleşmiş şeyle devam etti, ve şimdi daha fazla soru ile geri döndüm. :)

Overview


Goals

İşte bu çiftleşmiş motoru için hedefleri şunlardır:

  • minimal sözdizimi.
  • temiz php kod üretmek.
  • html dizim bozmazlar.
  • php geliştiricileri yeni bir şey (iyi, çok değil) öğrenmek gerek.
  • php akış kontrolü çoğu destek (her şey ama yapmak .. iken).
  • inline php desteği.

Umarım bu oldukça iyi geliyor. O not hedefleri arasında fark ya da "X yapıyor şablon yazarlar önlemek" gibi şeyler vardır "şablonları anonim kullanıcılar tarafından temin edilecektir." Güvenlik burada not büyük bir endişe, bu normal olmayan bir şablonu php dosyasında olacağını daha başka olduğunu.

Rules

  • default escape sequence is {{...}}.*
    • if no other rules match, echo or evaluate the sequence
      • dizisi, bir noktalı virgül ile sona ererse, tüm dizisini değerlendirmek
      • aksi halde, ilk ifade yankı ve geri kalan değerlendirmek
  • {{for|foreach|if|switch|while (...):}} begins a block.
    • durumda parantez atlanabilir
    • kolon atlanabilir
    • Dış sağ dirseği dirsek eşleştirme için ihmal edilebilir. **
  • {{else|elseif|break|continue|case|default}} do what you'd expect.
    • durumda parantez atlanabilir
    • Dış sağ dirseği dirsek eşleştirme için {{case}} üzerine atlanabilir.
    • Dış sol dirseği dirsek eşleştirme için {{break|continue}} üzerine atlanabilir.
  • {{end}} ends a block.
    • kelime karakterler, 'sonuna' kadar eklenebilir mesela 'End_if'
    • Dış sol dirseği dirsek eşleştirme için ihmal edilebilir.

* custom brackets can be used.
** bracket matching syntax can be disabled.

Templating

Şimdiye kadar biz gerçekten sadece <?php...?> ve <?=...?> için bir yedek sözdizimi ile geldim. Bu gerçekten yararlı olabilmesi için, bazı çiftleşmiş-özel operasyon gerekir.

Ben çalıştığım bir diğer çiftleşmiş çerçeve de burada çalışması gerektiğini basit bir kap / içerik paradigma kullanır. Bu şablon sistemi xml tabanlı, bu yüzden kod böyle bir şey olmazdı ...

<!-- in a template -->
<html>
  <head>
    <tt:Container name="script" />
  </head>
  <body>
    <tt:Container name="main" />
  </body>
</html>

<!-- in a page -->
<tt:Content name="script">
  <script src="foo.js"></script>
</tt:Content>
<tt:Content name="main">
  <div>...</div>
</tt:Content>

Aynı isimde bir içerik alanının birden fazla deklare önceki içeriğini değiştirir, ancak önceki içeriği kadar, Konteyner yoluyla İçerik etiketi içinde geçerli olacaktır:

<tt:Content name="script">
  <script src="foo.js"></script>
</tt:Content>
...
<tt:Content name="script">
  <script src="bar.js"></script>
  <tt:Container name="script" />
</tt:Content>
...
<tt:Container name="script" />

Should çıkışı:

  <script src="bar.js"></script>
  <script src="foo.js"></script>

I set ve bu yeni çiftleşmiş sistemde get etiketleri ile Content ve Container yeniden denedim. Bunlar tabii, onlar xml etiketleri değil, dışında tam olarak aynı şekilde çalışması için tasarlanmıştır ediyoruz.

Code


Lafı daha fazla uzatmadan:

<?php

class Detemplate {

  public  $container_prefix='_tpl_';
  public  $brackets='{}';
  public  $bracket_matching=true;
  public  $use_cache=false;

  private $block_keywords=array('for','foreach','if','switch','while');
  private $set_count;
  private $get_count;

  public function parse_file ($file, $vars=array()) {
    $sha1=sha1($file);
    $cache = dirname(__FILE__)."/cache/".basename($file).".$sha1.php";
    $f = "{$this->container_prefix}page_{$sha1}_";
    if (!$this->use_cache || !file_exists($cache) || filemtime($cache)<filemtime($file)) {
      $php =  "<?php function $f {$this->t_vars()} ?>".
              $this->parse_markup(file_get_contents($file)).
              "<?php } ?>";
      file_put_contents($cache, $php);
    }
    include $cache;
    $f($vars);
  }

  public function parse_markup ($markup) {

    $blocks=implode('|', $this->block_keywords);

    $arglist= '\s*[\s(](.*?)\)?\s*';  // capture an argument list
    $word=    '\s*(\w+)\s*';          // capture a single word

    $l='\\'.$this->brackets{0}; // left bracket
    $r='\\'.$this->brackets{1}; // right bracket

    $dl="#$l$l";
    $sl=$this->bracket_matching ? "#$l?$l" : $dl;
    $dr="$r$r(?!:$r)#"; 
    $sr=$this->bracket_matching ? "$r$r?(?!:$r)#" : $dr; 

    $markup=preg_replace_callback(
      array (
        $sl.'(end)[_\w]*\s*;?\s*'.$dr,
        $dl.'(el)se\s*if'.$arglist.':?\s*'.$dr,
        $dl.'(else)\s*:?\s*'.$dr,
        $dl.'(case)'.$word.':?\s*'.$sr, 
        $dl.'(default)()\s*:?\s*'.$sr,
        $sl.'(break|continue)\s*;?\s*'.$dr,
        $dl.'(set)'.$word.':?\s*'.$sr, 
        $dl.'(get)'.$word.':?\s*'.$dr, 
        $dl.'(parse)'.$word.':?\s*'.$dr, 
        $dl.'(function|fn)'.$word.$arglist.':?\s*'.$sr,
        $dl.'('.$blocks.')'.$arglist.':?\s*'.$sr,
        '#('.$l.$l.')(.+?)(;?)\s*'.$dr, 
        '#\s*(\?)>[\s\n]*<\?php\s*#',
      ),
      array($this, 'preg_callback'),
      $markup);

    return $markup;

  }

  private function preg_callback ($m) {

    switch ($m[1]) {

      // end of block

      case "end":
        return "<?php } } ?>";

      // keywords with special handling

      case "el": // elseif
        return "<?php } elseif ({$m[2]}) { ?>";
      case "else":
        return "<?php } else { ?>";

      case "case": case "default":
         return "<?php {$m[1]} {$m[2]}: ?>";

      case "break": case "continue":
        return "<?php {$m[1]}; ?>";

      // parse an external template document

      case "parse":
        return $this->parse_markup(file_get_contents($m[2]));

      // save / load content sections

      case "set":
        $i=++$this->set_count[$m[2]];
        $f=$this->t_fn($m[2], $i);
        $p=$this->t_fn($m[2], $i-1);
        $v=$this->t_fn_alias($m[2]);
        return  "<?php if (!function_exists('$f')) { $v='$f'; ".
          "function $f {$this->t_vars()} unset ($v); $v='$p'; ?>";

      case "get":
        $i=++$this->get_count[$m[2]];
        $c=$this->t_fn_ctx($m[2], $i);
        $v=$this->t_tmp();
        $a=$this->t_fn_alias($m[2]);
        return  "<?php if (!$c) { ".
          "foreach (array_keys(get_defined_vars()) as $v) $c".  
          "[$v]=&\$$v; unset($v); } $a(&$c); ?>";


      case "function": case "fn":
        return "<?php if (!function_exists('{$m[2]}')) { ".
          "function {$m[2]} ({$m[3]}) { ?>";

      // echo / interpret

      case "{{":
        return "<?php".($m[3]?"":" echo")." {$m[2]}; ?>";

      // merge adjacent php tags

      case "?": 
        return " ";
    }

    // block keywords
    if (in_array($m[1], $this->block_keywords)) {
      return "<?php { {$m[1]} ({$m[2]}) { ?>";
    }

  } 

  private function t_fn ($name, $index) {
    if ($index<1) return "is_null";
    return "{$this->container_prefix}{$name}_$index";
  }

  private function t_fn_alias ($name) {
    return "\${$this->container_prefix}['fn_$name']";
  }

  private function t_fn_ctx ($name, $index) {
    return "\${$this->container_prefix}['ctx_{$name}_$index']";
  }

  private function t_vars () {
      $v=$this->t_tmp();
      return "($v) { extract($v); unset($v);";
  }

  private function t_tmp () {
      return '$'.$this->container_prefix.'v';
  }


}

?>

Örnek şablonu html:

<script>var _lang = {{json_encode($lang)}};</script>
<script src='/cartel/static/inventory.js'></script>
<link href='/cartel/static/inventory.css' type='text/css' rel='stylesheet' />

<form class="inquiry" method="post" action="process.php" onsubmit="return validate(this)">

  <div class="filter">
    <h2>{{$lang['T_FILTER_TITLE']}}</h2> 
    <a href='#{{urlencode($lang['T_FILTER_ALL'])}}' onclick='applyFilter();'>{{$lang['T_FILTER_ALL']}}</a>
  {{foreach ($filters as $f)}}
    <a href='#{{urlencode($f)}}' onclick='applyFilter("c_{{urlencode($f)}}");'>{{$f}}</a>
  {{end}}
  </div>

  <table class="inventory" id="inventory_table">  

  {{foreach $row_array as $row_num=>$r}

    {{if $row_num==0}

    <tr class='static'>
      {{foreach $r as $col}
      <th>{{$col}}</th>
      {end}} 
      <th class='ordercol'>{{$lang['T_ORDER']}}</th>
    </tr>

    {{else}}


    {{function spin_button $id, $dir, $max}
    <a href='#' class='spinbutton' 
       onclick="return spin('{{$id}}', {{$dir}}, {{$max}})">
      {{$dir==-1 ? '&#x25C0;' : '&#x25B6;'}}
    </a>
    {end}}

    <tr class="{{'c_'.urlencode($r[$man_col])}}">
      {{foreach $r as $i=>$col}
      <td class='{{$i?"col":"firstcol"}}'>{{$col}}</td>
      {end}}
      <td class='ordercol'>
        {{$id="part_{$r[$part_col]}"; $max=$r[$qty_col];}}
        {{spin_button($id, -1, $max)}}
        <input  onchange="spin(this.id, 0, '{{$max}}')" 
                id='{{$id}}' name='{{$id}}'type='text' value='0' />
        {{spin_button($id, +1, $max)}}
      </td>
    </tr>

    {end}}


  {end}}

    <tr class="static"><th colspan="{{$cols+1}}">{{$lang['T_FORM_HELP']}}</th></tr>

  {{foreach $fields as $f}

    <tr class="static">
      <td class="fields" colspan="2">
        <label for="{{$f[0]}}">{{$f[1]}}</label>
      </td>
      <td class="fields" colspan="{{$cols-1}}">
          <input name="{{$f[0]}}" id="{{$f[0]}}" type="text" />
      </td>
    </tr>

  {end}}

    <tr class="static">
      <td id="validation" class="send" colspan="{{$cols}}">&nbsp;</td>
      <td colspan="1" class="send"><input type="submit" value="{{$lang['T_SEND']}}" /></td>
    </tr>

  </table>

</form>

Questions


Ben bu şeyle devam etmek hakkında bir kaç soru var. Bazı kesin cevaplar var, biraz daha CW malzeme olabilir ...

  • set / get dağınık kod üretir. Geliştirilebilir mi? Ben set arasında mantıklı orta yere çeşit arıyorum / almak ve {{function}} (kod ve örneğe bakın).

  • Ne bu popüler çiftleşmiş dilde sunulan neler eksik?

  • Sözdizimi Tamam mı? Şeyler, bir şeyler yapmak çizgileri ve akış kontrol hatları yankı hatları daha sözdizimsel farklı olmalıdır? Nasıl eşleşen için opsiyonel dış destekleri hakkında ... aptalca?

Bu konuda herkesin girişini haber bekliyorum.

0 Cevap