Wie HTML Schnipsel zusammensetzen und ausgeben?
MB
- php
- programmiertechnik
Moin Community,
wie bekomme ich im View des MVC Pattern hin, das der HTML-Code nicht sofort per include dargestellt, sondern erst im "Buffer" gespeichert und dann ausgegeben wird.
Da ja die HTML-Templates verschachtelt weden müsse bin ich auf folgendes gestoßen,
ob_start()
und ob_get_clear()
ist eine schöne Methode von einem Tutor wo man einfach mit include()
arbeiten kannecho '<html>'; include $header(); include $content(); include $footer(); echo '</html>
ist aber nicht mein Stilfile_get_content()
ist auch spannend da man wahweise laden, einbinden und ausgeben kann! (Habe ich auch hier aus dem Forum).Ich möchte schon gern alle Views in einem Packet verschnürt und dann ausgegeben. Für mich eleganter anstatt sequentiell zu arbeiten und Code auseinander zu brechen. Gibts da as in der Performance was ich bei diesen lösungen beachten sollte? Wenn Fragen sind, bitte präzise stellen.
vlg MB
Das kannst du prinzipiell so machen. Ich weiß nicht, wie man darauf präziser antworten sollte.
Hello,
Das kannst du prinzipiell so machen. Ich weiß nicht, wie man darauf präziser antworten sollte.
Man müsste!
Aber dann würde die Antwort sehr lang werden müssen.
Ich habe schon drei Anläufe genommen und musste feststellen, dass Tim uns Anno 1989 ein ganz blödes Ei gelegt hat mit HTML & Co.
Es wurden diverse Dinge vermischt, die man besser auseinander gehalten hätte. Man hätte die Modularität nicht zur Atomarität treiben dürfen...
Liebe Grüße
Tom S.
@@TS
Ich habe schon drei Anläufe genommen und musste feststellen, dass Tim uns Anno 1989 ein ganz blödes Ei gelegt hat mit HTML & Co.
Es wurden diverse Dinge vermischt, die man besser auseinander gehalten hätte. Man hätte die Modularität nicht zur Atomarität treiben dürfen...
Du sprichst in Rätseln. Da widme ich mich lieber dem Matherätsel; das ist einfacher zu lösen.
LLAP 🖖
moin Gunnar,
nebenbei: wenn man die gegebenen Mittel hat, um solche Aufgaben zu lösen, wäre das vermutlich einfacher, jedoch fehlern mir diese mittel was ich sehr bedauere 😕.
vlg MB
Hallo MB,
wenn Du die Matheaufgabe meinst - da brauchst Du Schulmathematik der Mittelstufe und eine gedankliche Hilfslinie 😀
Rolf
Wie erwähnt habe ich Mathe LK im Fach-Abi. Ich hab dann leider Gottes aufgehört und nich mehr weiter gemach, da viele Dinge für mein Leben wichtiger waren. Ich kann diese Aufgabe jetzt nicht mehr lösen :'( aber ich würde die Herleitung begreifen.
ok nach längerem hinsehen und sehr viele male die Aufgabe lese is das mit taschenrechner der sinus funktion hat und pythagoras wirklich sehr einfach. Ich hab zuerst einfach die Frage nicht verstanden und zum anderen assoziiere ich mit kreisen die Taylor-Reihe.
@@MB
ok nach längerem hinsehen und sehr viele male die Aufgabe lese is das mit taschenrechner der sinus funktion hat und pythagoras wirklich sehr einfach.
Wenn du für die Aufgabe den Sinus oder einen Taschenrechner brauchst, hast du nicht den einfachen Lösungsweg gefunden.
LLAP 🖖
moin mermshaus,
vielen dank für deinen zuspruch? Welche Methode soll ich den nun nehmen? ob_start()
, sequenzielles include
oder file_get_contents()
?
welcher Vorteile / Nachteile bietet es mir?
vlg MB
Das ist jetzt eine völlig andere Frage als in deinem Ausgangsbeitrag. 😉 Aus Performance-Sicht kann das grundsätzlich auf jede von dir genannten Weise umgesetzt werden. Es gibt keine prinzipiellen Bedenken, die gegen irgendwas davon sprechen.
Output-Buffering ist in diesem Kontext eine Hilfsmechanik, um beispielsweise in PHP-Templates den „HTML-Modus“ nutzen zu können (Direktausgaben außerhalb von <?php…?>
-Tags) und um dennoch die Template-Rückgabe erst mal als String weiterverarbeiten zu können. Das ist grundsätzlich durchaus sinnvoll, weil dadurch möglicherweise vermieden wird, alle HTML-Ausgaben umständlich als PHP-Strings zusammenbauen zu müssen, was unleserlich ist. Zudem kann mit Output-Buffering vermieden werden, halbfertige Seiten auszuliefern, wenn in den Templates Fehler auftreten. In diesem Fall kann der bisher generierte Ausgabe-Buffer verworfen und eine neue Fehlerseite erzeugt werden. Ein Nachteil in manchen Fällen ist, dass der gesamte Inhalt oder große Teile des Inhalts gleichzeitig im Speicher gehalten werden. Das ergibt bei Downloads zum Beispiel wenig Sinn. Bei normalen HTML-Seiten ist es recht egal, solange keine besonderen Anforderungen vorliegen.
Includes binden weitere PHP-Dateien ein und führen den Inhalt dabei als Code aus. Das ist im Templating hilfreich, wenn PHP als Templatesprache genutzt wird, da damit in Template-Dateien auf Variablen und die üblichen Kontrollstrukturen (Bedingungen, Schleifen, …) zurückgegriffen werden kann, was im Grunde essenzielle Funktionalität ist. Die Alternative dazu sind Template-Engines mit eigener Syntax, die diese Konstrukte anbietet. (Die kompilieren aber in der Regel aus Geschwindigkeitsgründen den eigenen Code auch nach PHP.)
file_get_contents
bietet in dem Sinne nur sehr eingeschränktes Templating, weil von sich aus in der eingebundenen Datei kein Logikcode (Variablen, Schleifen, …) ausgeführt wird. Für das Einbinden rein statischer Inhalte ist die Funktion grundsätzlich nutzbar, aber wenn ansonsten sowieso „echtes“ Templating mit Logikcode in Templates genutzt wird, kann auch ein statischer HTML-Inhalt problemlos auf die „echte“ Weise eingebunden werden. file_get_contents
ist dann eher für Inhalte, in denen by design kein PHP-Code direkt ausgeführt werden darf, weil es sich vielleicht um User-Uploads handelt oder dergleichen.
* * *
Den Ansatz, in jeder Template-Seite explizit Header und Footer zu inkludieren, halte ich für nicht so praktisch. Ich würde auf eine geschachtelte Struktur setzen, in der der eigentliche Seiteninhalt erzeugt wird, der dann in ein HTML-Rahmenlayout eingefügt wird. Das ist mit PHP recht simpel zu bauen, aber ähnliche Konzepte gibt es in Template-Engines wie Twig auch bereits integriert:
Für kleine Sachen nutze ich oft Code, der grob so aussieht:
(Anmerkung: In den Beispielen fehlt aus Gründen der Lesbarkeit gegebenenfalls Escaping bei Kontextwechseln (htmlspecialchars
).)
function render($__templateFile, array $tpl = array())
{
require __DIR__ . '/view/' . $__templateFile . '.phtml';
}
Das rufe ich dann zum Beispiel so auf:
// Template-Werte für Index-Seite
$vars = array(
'posts' => getNewestPosts()
);
render('layout', array(
'title' => 'Homepage',
'content' => render('index', $vars)
));
layout.phtml:
<!doctype html>
<html lang="de">
<meta>
...
<title><?=$tpl['title']?></title>
...
</meta>
<body>
...
<?=$tpl['content']?>
...
</body>
</html>
index.phtml:
<h1>Startseite</h1>
<?php foreach ($tpl['posts'] as $post): ?>
<?php render('_post', array('post' => $post)); ?>
<?php endforeach; ?>
Das kommt in diesem Fall ohne Output-Buffering aus und lässt sich natürlich beliebig eleganter gestalten. Zum Beispiel mit eigenen View-Klassen. Das würde ich mir bei Interesse ruhig mal in einem der verbreiteten Frameworks (Laravel, Symfony, Zend, Yii, …) anschauen.
Hello,
Output-Buffering ist in diesem Kontext eine Hilfsmechanik, um beispielsweise in PHP-Templates den „HTML-Modus“ nutzen zu können (Direktausgaben außerhalb von
<?php…?>
-Tags) und um dennoch die Template-Rückgabe erst mal als String weiterverarbeiten zu können.
Jetzt ist bei mir gerade eine Lampe angegangen :-)
Die Frage sollte nicht lauten: Output-Buffer oder nicht?
Die Frage sollte lauten: Single-Pass oder Multi-Pass?
##Was ich damit meine?
Es gibt immer Schwierigkeiten damit, revolvierende Ausgaben in statische Templates einzubauen. Ob eine Ausgabe revolvierend ist, oder nicht, ist meistens von den Daten abhängig. Eine Tabelle kann mehrere Zeilen enthalten, muss aber nicht. Wieviele es werden, weiß man erst, wenn die Daten ebenfalls zur Verfügung stehen. Das Mustertemplate kann man aber bereits vorher bauen, anschauen, stylen, evaluieren, usw.
Per PHP-DOM-Parser kann man die Anzahl der Zeilen auch wunderbar erweitern, wenn notwendig, oder die Tabelle ganz ersetzen, wenn gar keine Daten vorhanden sind.
Und am Ende setzt man dann die reinen (kontextbehandelten!) Daten in das fertige HTML-Template ein. Und dann wird die Ausgabe in den Buffer geschrieben / aka ausgegeben.
Liebe Grüße
Tom S.
Ja, ein wenig geht es wohl in die Richtung.
Ich würde aber sagen, dass die vorherrschende Strategie im Templating derzeit schon single-pass ist, auch wenn das gerade beim Einsatz von Template-Engines oder komplexen View-Objekt-Modellen vielleicht nicht immer so ganz trennscharf ist und auch weil man den Ansatz, nachträglich noch Elemente zu verändern, durchaus manchmal antrifft. Serverseitig halte ich das aber für eher unüblich.
XML-/XSL-basierte (oder auch DOM-basierte) Templating-Ansätze gibt es auch in PHP (PHPTAL etwa), aber so wirklich relevant ist das in meiner Wahrnehmung nicht, weil es vergleichsweise umständlich ist (die XML-Verarbeitung in PHP hat so ihre Eigenheiten und auch XSLT schreibt niemand freiwillig, glaube ich) und in der Ausführung ziemlich teuer. Zudem muss man prinzipiell klar konstatieren, dass die Versuche, HTML in XML zu formulieren und als Standard zu etablieren, gescheitert sind und im Grunde keine praktische Relevanz mehr haben. (Wobei XML aber schon ungleich DOM ist.)
Ich habe hier…
render('layout', array(
'title' => 'Homepage',
'content' => render('index', $vars)
));
…beim Schreiben aus dem Kopf ein wenig Mist gebaut (und kann nicht mehr editieren). Das funktioniert so nicht, weil render
direkt Ausgabe generiert, hier aber einen String liefern müsste.
Schneller Fix:
ob_start();
render('index', $vars);
$content = ob_get_clean();
render('layout', array(
'title' => 'Homepage',
'content' => $content
));
Dann stimmt auch die Aussage weiter unten nicht mehr, dass der Code ohne Output-Buffering auskommt. (Man kann das prinzipiell aber entsprechend arrangieren, wenn man etwas mehr Infrastruktur baut und Closures oder Objekte nutzt, die dann immer erst bei Bedarf nach HTML gerendert werden. Das ist meines Erachtens aber wie gesagt nicht unbedingt eine Eigenschaft, die zwingend erstrebenswert ist.)