Ankündigung

Einklappen
Keine Ankündigung bisher.

Template oder Includes?

Einklappen

Neue Werbung 2019

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Template oder Includes?

    Hallo Leute,

    ich habe zwar bereits ein ganzes CMS programmiert, aber ich habe von einer eigentlich grundsätzlichen Sache gar keine Ahnung Ich mache das ganze nur nebenbei und aus Spaß, nicht beruflich oder so.

    Wo genau liegt eigentlich der Unterschied zwischen templates und includes?

    Sagen wir ich habe eine beliebige Seite und unten soll ein Footer-Element in dem z.B. Links zum Impressum, zum Kontaktformular o.Ä. angezeigt werden sollen. Bisher habe ich das so gelöst, dass dann am Ende einfach eine footer.php mittels include 'footer.php'; eingebunden habe. Das würde aber ja auch mittels include 'templates/footer.tpl.php'; gehen. Was wären die Vor- / Nachteile davon? Google hat mir nicht wirklich geholfen.

    Danke sehr!


  • #2
    Kurz gesagt, es kann bei einer konkreten Implementierung sein, das "Template laden" und "Datei includen" letztlich auf das gleiche hinausläuft. Dann ist die Unterscheidung gar nicht notwendig.

    Beim Framework Laravel ist das der Fall. Es werden sogenannte Engines benutzt um Templates zu laden. Die mitgelieferte Klasse PhpEngine macht aber letztlich nichts anderes, als per include eine Template-Datei zu inkludieren:
    PHP-Code:
    // (Anmerkung: $__path ist der Dateiname, $__data ein Array mit Variablen die im Template benutzt werden koennen)
    protected function evaluatePath($__path$__data)
        {
            
    $obLevel ob_get_level();
            
    ob_start();
            
    extract($__data);
            
    // We'll evaluate the contents of the view inside a try/catch block so we can
            // flush out any stray output that might get out before an error occurs or
            // an exception is thrown. This prevents any partial views from leaking.
            
    try
            {
                include 
    $__path;
            }
            catch (\
    Exception $e)
            {
                
    $this->handleViewException($e$obLevel);
            }
            return 
    ltrim(ob_get_clean());
        } 
    Quelle: https://github.com/laravel/framework...Engine.php#L24

    Die Methode erwartet also eine PHP-Datei.

    Wie man allerdings sieht, findet das Inkludieren im Scope einer Methode statt. Bei deiner Variante stehen alle Variablen aus dem Parent-Template automatisch auch im Child-Template zur Verfügung. Das ist bei Laravel nicht so (aber auf anderem Weg auch möglich, wenn man es explizit wünscht). Außerdem kann man vor (und nach) dem Inkludieren noch irgend was tun, z. B. wie in der Methode zu sehen Exceptions abfangen. Das kann man natürlich nicht, wenn man direkt im Template include benutzt. Klar, das ist trivaler Weise so.

    Es dürfte dir klar sein, dass include jedenfalls nur mit PHP-Dateien funktioniert. Nutzt man aber eine Template-Engine, die eine eigene Syntax mitbringt, kann man include idR nicht verwenden, auch wenn die Engine die Template-Dateien zu PHP-Dateien kompiliert. Man möchte schließlich auf das Template verweisen und nicht auf das Kompilat. Ebenfalls kann man include offensichtlich nicht verwenden, wenn die Template-Engine das Einbinden von PHP-Code nicht erlaubt. Manche Engine tun das und bringen eine ganz eigene Syntax mit. Dann ist man automatisch gezwungen, auch etwaige Template-Befehle zu nutzen.

    Hm, ich hoffe du kannst was mit meinem Geschreibsel etwas anfangen. Irgendwie ist es mir hervorragend gelungen, nicht auf den Punkt zu kommen. Sorry dafür.

    Vielleicht noch ein Versuch:
    So wie du das machst, sind Templates im Grunde nichts anderes als PHP-Dateien. Ob du die dann in ein eigenes Verzeichnis schiebst und ihnen eine eigene Endung gibst, ändert daran nichts. Erst wenn man wirkliche Template-Engines verwendet, wird aus einer PHP-Datei mehr. Das wird besonders offensichtlich bei Template-Engines, die für ihre Templates eine eigene Syntax vorschreiben (Beispiel: Twig). Diese Templates werden dann im Regelfall zunächst in PHP-Templates übersetzt (kompiliert), ehe sie tatsächlich verwendet werden können. Vor dem Kompilieren wäre es sinnfrei, sie mit include einzubinden, weil PHP mit der spezifischen Syntax der Templates nichts anfangen und Template-Befehle ignorieren würde.

    So, ich glaube das ist verständlicher als der ganze erste Roman.

    Kommentar


    • #3
      Sehr richtig monolith, aber der umgekehrte Fall ist viel entscheidender.
      Ein Template laden und darstellen kann u.U. ohne include stattfinden. PHP Code würde dann nicht ausgeführt werden.
      Über 90% aller Gewaltverbrechen passieren innerhalb von 24 Stunden nach dem Konsum von Brot.

      Kommentar


      • #4
        Ja. Habe ich inzwischen hoffentlich auch herausgestellt. Ich glaube, man sollte keine 30 Minuten an einem Post herumeditieren. Das führt zu Problemen mit der Nebenläufigkeit aka Posts anderer User

        Kommentar


        • #5
          Man kann im übrigen auch Exceptions die in einem Template geworfen werden in den post-buffering scope verschieben. Laravel macht das ähnlich, allerdings auf einer ganz anderen Ebene.

          Damit du einen Ansatz hast wie sowas generell ( generisch ) aussehen kann, hier eine Beispiel-Implementierung:

          Engine
          PHP-Code:
          class Engine {
              
              protected 
          $functions = [];
              
              public function 
          __construct()
              {
                  
          $engine $this;
                  
                  
          $this->registerFunction(
                      
          'render'
                      function(
          $filename, array $assignments = []) use ($engine) {
                          return 
          $engine->render($filename$assignments);
                      }
                  );
              }
              
              public function 
          registerFunction($nameClosure $callback)
              {
                  
          $this->functions[strtolower($name)] = $callback;
              }
              
              public function 
          render($filename, array $assignments = [])
              {
                  if ( ! 
          is_file($filename) ) {
                      throw new 
          DomainException('Template file not found: '.$filename);
                  }
                  
                  
          $handler = new Template($assignments$this->functions);
                  
                  
          $compiler = function() use ($filename)
                  {
                      
          ob_start();
                      try {
                          include 
          $filename;
                      }
                      catch ( 
          Exception $exception ) {
                          
          ob_end_clean();
                          throw 
          $exception;
                      }
                      
                      
          $content ob_get_contents();
                      
          ob_end_clean();
                      
                      return 
          $content;
                  };
                  
                  return 
          call_user_func($compiler->bindTo($handler));
              }
              

          Template Handler:
          PHP-Code:
          class Template {
              
              protected 
          $assignments = [];
              protected 
          $functions = [];
              
              public function 
          __construct(array $assignments, array $functions)
              {
                  
          $this->assignments $assignments;
                  
                  foreach (
          $functions as $name => $callback ) {
                      
          $this->functions[$name] = $callback->bindTo($this);
                  }
              }
              
              public function 
          call($function, array $params)
              {
                  
          $function strtolower($function);
                  
                  if ( ! 
          array_key_exists($function$this->functions) ) {
                      throw new 
          DomainException('unknown template function: '.$function);
                  }
                  
                  return 
          call_user_func_array($this->functions[$function], $params);
              }
              
              public function 
          __get($assignment)
              {
                  if ( ! 
          array_key_exists($assignment$this->assignments) ) {
                      throw new 
          DomainException('unknown template assignment: '.$assignment);
                  }
                  
                  return 
          $this->assignments[$assignment];
              }
              
              public function 
          __set($assignment$value)
              {
                  
          $this->assignments[$assignment] = $value;
              }
              
              public function 
          __isset($assignment)
              {
                  return 
          array_key_exists($assignment$this->assignments);
              }
              

          test-template.phtml
          HTML-Code:
          <p>Hello <?= $this->name ?>!</p>
          Usage:
          PHP-Code:
          $engine = new Engine();
          echo 
          $engine->render('test-template.phtml', ['name' => 'world']); 
          Output:
          HTML-Code:
          <p>Hello world!</p>
          Viel Erfolg
          [URL="https://gitter.im/php-de/chat?utm_source=share-link&utm_medium=link&utm_campaign=share-link"]PHP.de Gitter.im Chat[/URL] - [URL="https://raindrop.io/user/32178"]Meine öffentlichen Bookmarks[/URL] ← Ich habe dir geholfen ? [B][URL="https://www.amazon.de/gp/wishlist/348FHGUZWTNL0"]Beschenk mich[/URL][/B].

          Kommentar


          • #6
            Zitat von monolith Beitrag anzeigen
            Es dürfte dir klar sein, dass include jedenfalls nur mit PHP-Dateien funktioniert.
            Das ist nicht ganz klar formuliert. Natuerlich kann ich beliebige Dateien (beispielsweise reine .html oder .js-Dateien) inkludieren. Allerdings werden hier dann auch PHP-Tags ausgefuehrt. Das kann von Belang sein. Ich mache ab und zu so was:

            PHP-Code:
            <script type="...">
                <?= $this->render('script/app.js'?>
            </script>
            Zitat von monolith Beitrag anzeigen
            Erst wenn man wirkliche Template-Engines verwendet, wird aus einer PHP-Datei mehr.
            Für mich sind zwei Dinge besonders wichtig und machen den eigentlichen Unterschied zwischen einer Template-Engine und einer normalen PHP-Datei aus: layouting und sanitizing.

            Layouting: Man überschreibt nur noch die Teile einer HTML-Datei, die sich für meine aktuelle Sicht ändern. Die restlichen Sektionen werden mit Defaults gefüllt.

            PHP-Code:
            <?php $this->layout('../layouts/zweispaltiges-layout.phtml'?>

            <?php $this->region('content'?>
            hier steht mein content
            <?php $this->end() ?>
            PHP-Code:
            <html>
                ...
                <body>
                    <aside id="left">
                        <?php $this->placeholder('left'?>
                            Das hier kommt, wenn kein Inhalt angegeben wurde
                        <?php $this->end() ?>
                    </aside>
                    <main id="content">
                        <?php $this->placeholder('content'?>
                            Das hier kommt, wenn kein Inhalt angegeben wurde
                        <?php $this->end() ?>
                    </main>
                </body>
            </html>
            Layouts können -wenn richtig eingesetzt- ein mächtiges Werkzeug sein. Ein Layout muss nicht immer ein öffnendes und schließendes <html>-Tag haben. Wenn man viele Templates hat, die im Grunde gleich aussehen, dann kann man sich wiederholende Muster in ein Layout packen und nur noch die Änderungen angeben. Der daraus erzeugte Inhalt wird dann wieder in einem anderen Template verwendet, dass dann ein Elementlayout nutzt, dass dann ein Bereichslayout nutzt, dass dann ein Hauptlayout nutzt.

            Santinizing auf der anderen Seite kann vor Fehlern schützen, wenn richtig eingesetzt. Es ist meiner Ansicht nach sinnvoll (auch wenn das schnell in Streit ausarten kann) keine Objekte an Templates zu übergeben. Der Grund ist einfach: Man kann ein Array leicht nachbauen und so das Template leicht wiederverwenden. Dem gegenüber steht die Möglichkeit, typisierte Datenstrukturen (Objekte) beim Refaktoring zu berücksichtigen (ändere ich irgendwo den Namen einer Methode, werden dabei auch Templates berücksichtigt). Aber anderes Thema. Gehen wir davon aus, dass wir hier leicht beeinflussbare Arrays als Datenbasis einsetzen:

            PHP-Code:
            <div>
                <?php $article $this->getArray('article'?>
                <div>
                    Art.Nr.: <?= $article->getString('refno''- nicht vorhanden -'?>,
                    Price: <?= $article->getFormat('price'Currency::class) ?>
                </div>
                <h1>
                    <?= $article->getString('name'?>
                </h1>
                <div>
                    <div>Ähnliche Artikel</div>
                    <?php foreach($article->getArray('references.similar') as $reference): ?>
                        <div><?= $reference->getString('refno'?> - <?= $reference->getString('name'?> - <?= $product->getFormat('price'Currency::class) ?></div>
                    <?php endforeach ?>
                </div>
            </div>
            Rekursive Strukturen werden von meiner TE frech wieder in ein Datenobjekt gewrappt, dass dann Methoden wie getBool, getInt, getString etc bereitstellt. getString im Speziellen reinigt (abhängig vom Ausgabekontext der TE) dann die Ausgabe. Im Falle vom HTML-Kontext wird immer ein htmlentities drüber ausgeführt. mit getRaw bekommt man die ungefilterten Daten. Dann weiss man aber auch, dass man ungeschützt unterwegs ist.

            Falls das durch meine Schreibart jetzt falsch rüberkommt: Ich will keinem meine Herangehensweise aufdrücken. Das ist nur meine Sicht auf die Dinge.

            Btw: Der Code ist nur Concept-Code
            Standards - Best Practices - AwesomePHP - Guideline für WebApps

            Kommentar

            Lädt...
            X