it-swarm.com.de

Wie strukturiere ich ein Template-System mit einfachem PHP?

Ich habe diese Frage im Stackoverflow gelesen:

https://stackoverflow.com/questions/104516/calling-php-functions-within-heredoc-strings

und die akzeptierte Antwort besagt, dass einfache PHP Vorlagen wie diese:

template.php:

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

index.php:

<? php 
 
 $ title = 'Demo Title'; 
 
 Funktion getContent () {
 return '<p> Hallo Welt! </p> '; 
} 
 
 include (' template.php '); 
 
?>

Für mich ist das Obige nicht gut strukturiert in dem Sinne, dass template.php von Variablen abhängt, die in anderen Skripten definiert sind. Und Sie verwenden ein include (), um Code auszuführen, wenn Sie include('template.php') ausführen (im Gegensatz zu include (), um eine Klasse oder eine Funktion einzuschließen, die nicht sofort ausgeführt wird).

Ich denke, ein besserer Ansatz besteht darin, Ihre Vorlage in eine Funktion zu verpacken:

template.php:

<? php 
 
 Funktionsvorlage ($ title, $ content) {
 ob_start (); ?> 
 
 <html> 
 <head> 
 <Titel> <?=$titel?> </ title> 
 </ Head > 
 <body> 
 <? = $ content?> 
 </ body> 
 </ html> 
 
 < ? php return ob_get_clean (); 
} 
 
?>

index.php:

<? php 
 
 require_once ('template.php'); 
 
 Druckvorlage ('Demo Title', '<p> Hello World! </ p > '); 
 
?>

Ist der zweite Ansatz besser? Gibt es einen noch besseren Weg, dies zu tun?

15
Ryan

Ich würde den zweiten Ansatz nicht machen, da die Parameter nicht benannt sind.

Ein gut geschriebenes Aufsatz über die Beschreibung, wie ein Vorlagensystem funktioniert sollte von Parr stammen, wird oft von Leuten zitiert, die Vorlagensysteme und/oder Web-MVC-Frameworks schreiben.

Persönlich bevorzuge ich normalerweise die Implementierung einer ArrayObject-Klasse mit einem Eigenschaftenarray, und die Vorlage verweist auf $this->propertyName, Was tatsächlich das $this->property['name'] Des Vorlagenobjekts ist. Dies könnte auch einfach durch Verwendung von __set Und __get Erreicht werden, also:

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

und eine Vorlage würde aussehen wie:

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

und es aufzurufen würde aussehen wie:

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

Soweit ich mich erinnere, sehen die alten Symfony 1.x- und die Zend_View-Template-Engines so aus, und für mich ist das in Ordnung.

12
Aadaam

Da Codeigniter mein Lieblingsframework ist, schlage ich Ihnen eine Codeigniter-ähnliche Lösung vor:

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

Ihre Vorlage würde folgendermaßen aussehen:

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

Und Sie würden es rendern, indem Sie die Klasse instanziieren, Daten in einem Array als Konstruktorparameter übergeben und die Methode 'render' aufrufen:

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

Auf diese Weise führen Sie den enthaltenen Code nicht direkt aus und halten Ihre Vorlage auch lesbar, sodass Designer zufrieden sind.

2
lortabac

Der Erste template.php ist einfacher zu laden wie es ist in dreamweaver/bluegriffon/was auch immer und von einem serverseitigen, nicht versierten Webdesigner bearbeitet, der zweite ... nun, es könnte immer noch irgendwie, aber es ist viel mehr wahrscheinlich während des Bearbeitungsprozesses brechen.

Ich würde mit dem ersten gehen, damit es so aussieht wie HTML mit Vorteilen, wie es Designer von Drittanbietern normalerweise bevorzugen.

1
ZJR

Eine Vorlage wird immer von externen Variablen abhängen, und da PHP eine dynamische Sprache ist), gibt es keine Möglichkeit, beim Kompilieren zu erzwingen, dass sie dort sein werden Der erste Ansatz ist wahrscheinlich in Ordnung, es gibt jedoch noch einige Probleme:

  • Das Beispiel kümmert sich nicht um die HTML-Codierung der Ausgabe, was bedeutet, dass Sie potenzielle XSS-Schwachstellen haben.
  • Wenn eine dieser Variablen nicht festgelegt ist, gibt der Code eine Warnung aus. Sie werden nicht sehen, ob die Warnung sinnvoll ist oder nicht (möglicherweise ist die Variable optional).

Ein sehr einfacher Ansatz besteht darin, eine Funktion zu schreiben, vorzugsweise mit einem sehr kurzen Namen, die sich um beide kümmert. es _() zu nennen scheint eine übliche Konvention zu sein. Eine einfache Version könnte folgendermaßen aussehen:

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

Und dann würden Sie in Ihrer Vorlage Folgendes tun:

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

Weitere Dinge, die mit der Funktion _() zu tun haben:

  • Geben Sie ein zweites Argument an, um das Überschreiben des Aufrufs htmlspecialchars zu ermöglichen, wenn Sie HTML anstelle von rohen Zeichenfolgen übergeben möchten.
  • Fügen Sie eine Typprüfung hinzu, damit Arrays und Objekte nicht Array und Object ergeben, sondern etwas Sinnvolles (oder eine leere Zeichenfolge).
  • Unterstützung für die Internationalisierung hinzufügen (ein weiteres Argument).
  • Drucken Sie im Debug-Modus den Namen der Variablen mit einer speziellen Formatierung, falls diese nicht definiert ist. Auf diese Weise können Sie auf einen Blick erkennen, ob mit der Vorlage etwas nicht stimmt.
1
tdammers