Şablon sistemi düz PHP kullanarak nasıl yapılandırılır?


15

Stackoverflow üzerinde bu soruyu okuyordu:

/programming/104516/calling-php-functions-within-heredoc-strings

ve kabul edilen cevap şöyle bir PHP şablonu yaptığını söylüyor:

template.php:

<Html>
    <Head>
        <Title> <? = $ Başlık?> </ Title>
    </ Head>
    <Body>
        <? = GetContent ()?>
    </ Body>
</ Html>

index.php:

<? Php

$ title = 'Demo Başlığı';

işlev getContent () {
    dönüş '<p> Merhaba Dünya! </p>';
}

( 'Template.php') içerir;

?>

Bana göre yukarıdakiler, template.php dosyasının diğer komut dosyalarında tanımlanan değişkenlere bağlı olması bakımından iyi yapılandırılmamıştır. Ve bunu yaparken kodu yürütmek için bir include () include('template.php')kullanıyorsunuz (bir sınıfı veya hemen yürütülmeyen bir işlevi eklemek için include () yöntemini kullanmak yerine) kullanıyorsunuz.

Daha iyi bir yaklaşım, şablonunuzu bir işlev içine sarmak gibi hissediyorum:

template.php:

<? Php

işlev şablonu ($ title, $ content) {
    ob_start (); ?>

<Html>
    <Head>
        <Title> <? = $ Başlık?> </ Title>
    </ Head>
    <Body>
        <? = $ İçeriği?>
    </ Body>
</ Html>

    php dönüşü ob_get_clean ();
}

?>

index.php:

<? Php

Require_once ( 'template.php');

yazdırma şablonu ('Demo Başlığı', '<p> Merhaba Dünya! </p>');

?>

İkinci yaklaşım daha mı iyi? Bunu yapmanın daha iyi bir yolu var mı?

Yanıtlar:


12

Parametreler isimlendirilmediğinden ikinci yaklaşımı yapmam.

Bir şablon sisteminin nasıl çalışması gerektiğini açıklayan iyi yazılmış bir makale Parr'dan geliyor, genellikle şablon sistemleri ve / veya web-mvc çerçeveleri yazan insanlar tarafından alıntılanıyor.

Şahsen, genellikle tercih ettiğim bir özellik dizisine sahip bir ArrayObject sınıfı uygulamaktır ve şablon $this->propertyName, aslında şablon nesnesinin olduğu anlamına gelir $this->property['name']. Bu ayrıca __setve kullanılarak da gerçekleştirilebilir __get:

class Template {
  private $_scriptPath=TEMPLATE_PATH;//comes from config.php
  public $properties;
  public function setScriptPath($scriptPath){
    $this->_scriptPath=$scriptPath;
  }
  public function __construct(){
      $this->properties = array();
  }
  public function render($filename){

   ob_start();
   if(file_exists($this->_scriptPath.$filename)){
     include($this->_scriptPath.$filename);
    } else throw new TemplateNotFoundException();
    return ob_get_clean();
  }
  public function __set($k, $v){
      $this->properties[$k] = $v;
  }
  public function __get($k){
      return $this->properties[$k];
  }
}

ve bir şablon şöyle görünecektir:

<html>
      <head>
         <title><?=$this->title?></title>
      </head>
      <body>Hey <?=$this->name?></body>
</html>

ve onu çağırmak şöyle görünecektir:

$view = new Template();
$view->title="Hello World app";
$view->properties['name'] = "Jude";
echo $view->render('hello.inc');

Hatırladığım kadarıyla, eski Symfony 1.x ve Zend_View şablon motorları böyle görünüyor ve benim için iyi.


TinyButStrong da benzer bir şey yapıyor
Izkata

bazı puanlar üzerinde döngü nasıl ele diyorsun? ayrı bir "alt" şablon kullanıyor musunuz?
Ryan

Ben sadece $ başlık veya $ adı, örneğin şablonda $ bu kullanarak kurtulmak için herhangi bir yolu olup olmadığını merak ediyorum.
Ryan

1
@Ryan Include deyiminden extract($this->properties);hemen önce özellikleri değişkenlere ayıklamak için kullanabilirsiniz .
Joyce Babu

2

Codeigniter benim favori çerçevem ​​olduğu için size bir Codeigniter-ish çözümü öneriyorum:

class Template {
    protected $path, $data;

    public function __construct($path, $data = array()) {
        $this->path = $path;
        $this->data = $data;
    }

    public function render() {
        if(file_exists($this->path)){
            //Extracts vars to current view scope
            extract($this->data);

            //Starts output buffering
            ob_start();

            //Includes contents
            include $this->path;
            $buffer = ob_get_contents();
            @ob_end_clean();

            //Returns output buffer
            return $buffer;
        } else {
            //Throws exception
        }
    }       
}

Şablonunuz şöyle görünecektir:

<html>
    <head>
        <title><?=$title?></title>
    </head>
    <body>
        <?=$content?>
    </body>
</html>

Sınıfı örnekleyerek, bir dizideki verileri yapıcı parametresi olarak geçirerek ve 'render' yöntemini çağırarak bunu gerçekleştirirsiniz:

$data = array('title' => 'My title', 'content' => 'My content');
$tmpl = new Template('template.php', $data);
echo $tmpl->render();

Bu şekilde, dahil edilen kodu doğrudan yürütmezsiniz ve ayrıca şablonunuzu okunabilir tutarsınız, böylece tasarımcılar mutlu olur.


1

Bir şablon her zaman dış değişkenlere bağlı olacaktır ve PHP dinamik bir dil olduğundan, derleme zamanında orada olacakları zorlamanın bir yolu yoktur. Dolayısıyla ilk yaklaşım muhtemelen iyidir; yine de birkaç sorun var:

  • Örnek, çıktıyı kodlayan HTML koduyla ilgilenmez, bu da potansiyel XSS güvenlik açıklarına sahip olduğunuz anlamına gelir.
  • Bu değişkenlerden biri ayarlanmazsa kod bir uyarı verir; uyarının anlamlı olup olmadığını görmezsiniz (belki değişken isteğe bağlıdır).

Çok basit bir yaklaşım, her ikisi ile de ilgilenen, tercihen çok kısa bir isimle bir fonksiyon yazmaktır; demek _(), ortak bir sözleşme gibi görünüyor. Basit bir sürüm şöyle görünebilir:

function _($raw) {
    if (isset($raw)) {
        return htmlspecialchars($raw);
    }
}

Ve sonra şablonunuzda şunları yaparsınız:

<title><?= _($title) ?></title>

İşlevle ilgili daha fazla şey _():

  • htmlspecialcharsHam dizelerden ziyade HTML'yi aktarmak istediğiniz durumlarda , çağrının geçersiz kılınmasına izin vermek için ikinci bir argüman verin .
  • Bu diziler ve nesneler vermez böylece tür denetlemesi ekleyin Arrayve Objectoldukça anlamlı bir şey (veya boş dize), ancak.
  • Uluslararasılaştırma desteği ekleyin (yine başka bir tartışma).
  • Hata ayıklama modundayken, değişkenin adını tanımlanmamışsa bazı özel biçimlendirmelerle yazdırın. Bu şekilde, şablonda bir sorun olup olmadığını görebilirsiniz.

1

Birincisi template.phpolduğu gibi yüklemek daha kolay dreamweaver / bluegriffon / ne olursa olsun ve sunucu tarafı anlayışlı olmayan bir web tasarımcısı tarafından düzenlenmiş, ikincisi ... yine de olabilir, ancak düzenleme işlemi sırasında kırılması çok daha olasıdır .

İlk olarak , üçüncü taraf tasarımcıların genellikle tercih ettiği gibi , avantajlı HTML gibi görünmesini sağlamak için giderdim .


ne anlamda? Yani sürükle ve bırak yöntemiyle değiştirilemez mi? metinsel olarak ikincisi ilkiyle aynıdır, ancak birkaç PHP satırı ile sarılmıştır. Bu yüzden her zaman bu yapıya sahip olacağını varsayarsak, onların elle düzenlemeleri daha zor olmaz.
Ryan

1
İyi bir şablon geliştiricilere mantıklı, harika bir şablon tasarımcılara mantıklı geliyor.
Citricguy

-3

Php bir programlama dili değildir. Dolayısıyla, dilinizde gerçek bir tür sistemi yoksa, güçlü bir şekilde yazılmış yazmak mümkün değildir. Ancak PHP-Storm gibi IDE'nizin istediğiniz numarayı yapmasına yardımcı olabilirsiniz ...

Görünüm tanımınız:

interface mySimpleView { 
  public function getTitle(); 
} 

Şablon dosyanız:

<?php
/**
* @var $this mySimpleView  <== Your IDE will try to use this type.
*/
?>

<h1><?= $this->getTitle() ?></h1>
<p><?= $this->getContent() ?></p> <!-- <= IDE will warn you !  -->
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.