Bagaimana cara menyusun sistem template menggunakan PHP biasa?

15

Saya membaca pertanyaan ini di stackoverflow:

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

dan jawaban yang diterima mengatakan untuk melakukan templat PHP biasa seperti ini:

template.php:

<html>
    <head>
        <title><?=$title?> </title>
    </head>
    <body>
        <? = getContent ()?>
    </body>
</html>

index.php:

<? php

$ title = 'Judul Demo';

function getContent () {
    return '<p> Hello World! </p>';
}

termasuk ('template.php');

?>

Bagi saya hal di atas tidak terstruktur dengan baik dalam arti bahwa template.php tergantung pada variabel yang didefinisikan dalam skrip lain. Dan Anda menggunakan include () untuk mengeksekusi kode ketika Anda melakukannya include('template.php')(bukan menggunakan include () untuk menyertakan kelas atau fungsi yang tidak segera dieksekusi).

Saya merasa pendekatan yang lebih baik adalah dengan membungkus template Anda di dalam suatu fungsi:

template.php:

<? php

templat fungsi ($ judul, $ konten) {
    ob_start (); ?>

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

    <? php return ob_get_clean ();
}

?>

index.php:

<? php

require_once ('template.php');

print template ('Demo Title', '<p> Hello World! </p>');

?>

Apakah pendekatan kedua lebih baik? Apakah ada cara yang lebih baik untuk melakukannya?

Ryan
sumber

Jawaban:

12

Saya tidak akan melakukan pendekatan kedua karena parameter tidak disebutkan.

Esai yang ditulis dengan baik untuk menggambarkan bagaimana sistem templat seharusnya bekerja berasal dari Parr, sering dikutip oleh orang yang menulis sistem templat dan / atau kerangka kerja web-mvc.

Secara pribadi, apa yang biasanya saya sukai adalah untuk mengimplementasikan kelas ArrayObject dengan array properti, dan template akan merujuk $this->propertyName, yang sebenarnya akan menjadi objek template $this->property['name']. Ini bisa juga dicapai hanya dengan menggunakan __setdan __get, jadi:

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];
  }
}

dan sebuah template akan terlihat seperti:

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

dan memohonnya akan terlihat seperti:

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

Sejauh yang saya ingat, ini adalah bagaimana Symfony 1.x dan mesin template Zend_View yang lama terlihat, dan bagi saya tidak masalah.

Aadaam
sumber
TinyButStrong juga melakukan hal serupa
Izkata
bagaimana Anda menangani perulangan beberapa skor katakan? apakah Anda menggunakan templat "sub" yang terpisah?
Ryan
saya bertanya-tanya apakah ada cara untuk menghilangkan menggunakan $ this dalam template, misalnya hanya $ title atau $ name.
Ryan
1
@Ryan Anda dapat menggunakan extract($this->properties);untuk mengekstrak properti ke dalam variabel, tepat sebelum pernyataan include.
Joyce Babu
1

Templat akan selalu bergantung pada variabel luar, dan dengan PHP sebagai bahasa yang dinamis, tidak ada cara untuk menegakkan pada waktu kompilasi bahwa mereka akan ada di sana. Jadi pendekatan pertama mungkin baik-baik saja; masih ada beberapa masalah:

  • Contoh ini tidak menangani pengkodean HTML output, yang berarti Anda memiliki kerentanan potensial XSS.
  • Jika salah satu variabel tersebut tidak disetel, kode akan memunculkan peringatan; Anda tidak akan melihat apakah peringatan itu masuk akal atau tidak (mungkin variabelnya opsional).

Pendekatan yang sangat mudah adalah menulis suatu fungsi, lebih disukai dengan nama yang sangat pendek, yang menangani keduanya; menyebutnya _()tampaknya menjadi konvensi umum. Versi sederhana mungkin terlihat seperti ini:

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

Dan kemudian di templat Anda, Anda akan melakukan:

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

Lebih banyak hal yang harus dilakukan dengan _()fungsi:

  • Berikan argumen kedua untuk memungkinkan overriding htmlspecialcharspanggilan, untuk kasus-kasus di mana Anda ingin meneruskan HTML ke dalamnya daripada string mentah.
  • Tambahkan pengecekan tipe sehingga array dan objek tidak akan menghasilkan Arraydan Object, tetapi sesuatu yang bermakna (atau string kosong).
  • Tambahkan dukungan internasionalisasi (argumen lain).
  • Saat dalam mode debug, cetak nama variabel dengan beberapa format khusus jika tidak ditentukan. Dengan cara ini, Anda dapat melihat sekilas jika ada yang salah dengan templat.
tammmer
sumber
1

Yang pertama template.phplebih mudah untuk memuat apa adanya ke dreamweaver / bluegriffon / apa pun dan diedit oleh perancang web non-savvy sisi-server, yang kedua ... well itu masih bisa, tetapi jauh lebih mungkin untuk istirahat selama proses pengeditan .

Saya akan menggunakan yang pertama untuk membuatnya tetap terlihat seperti HTML dengan manfaat , seperti yang biasanya disukai oleh desainer pihak ke-3.

ZJR
sumber
dalam arti apa? maksud Anda tidak dapat diubah menggunakan seret dan lepas? secara tekstual yang kedua sama dengan yang pertama tetapi dengan beberapa baris PHP melilit. Jadi dengan asumsi selalu memiliki struktur itu, tidak sulit bagi mereka untuk mengedit dengan tangan.
Ryan
1
Template yang bagus masuk akal bagi pengembang, template yang bagus masuk akal bagi para desainer.
Citricguy
1

Karena Codeigniter adalah kerangka kerja favorit saya, saya mengusulkan solusi Codeigniter-ish:

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

Template Anda akan terlihat seperti:

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

Dan Anda akan merendernya dengan membuat instance kelas, meneruskan data dalam array sebagai parameter konstruktor dan memanggil metode 'render':

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

Dengan cara ini Anda tidak secara langsung mengeksekusi kode yang disertakan, dan Anda juga membuat template Anda dapat dibaca, sehingga desainer akan senang.

lortabac
sumber
-3

Php bukan bahasa pemrograman. Jadi menulis dengan mengetik sangat tidak mungkin jika bahasa Anda tidak memiliki sistem tipe nyata. Tetapi Anda dapat membantu IDE Anda seperti PHP-Storm untuk melakukan trik yang Anda inginkan ...

Definisi tampilan Anda:

interface mySimpleView { 
  public function getTitle(); 
} 

File template Anda:

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

<h1><?= $this->getTitle() ?></h1>
<p><?= $this->getContent() ?></p> <!-- <= IDE will warn you !  -->
Roger Keulen
sumber
Saya suka jawaban ini (walaupun jelas "Php bukan bahasa pemrograman" selalu akan menjadi perdebatan.
Ronnie