• Jetzt anmelden. Es dauert nur 2 Minuten und ist kostenlos!

Template Inheritance - Wie?

newlord

Mitglied
Moin Moin

Vorab: Ich bin mir dessen bewusst, dass fertige Templating Engines wie Blade oder Twig jenes im Titel erwähnte Feature bieten und setze seit 4 Jahren freudig Blade ein. Ich bin aber nicht auf der Suche nach einer Fertiglösung, sondern will die Funktionsweise dahinter verstehen und dies mit Vanilla-PHP mal nachvollziehen.

In den letzten Tagen habe ich diverse Artikel darüber gelesen und mich durch einige Quellcodes auf GitHub gewühlt, aber *Klick* hat's noch nicht gemacht. Konkret geht's um Definierung von Blöcken im Master-Template und die Auffüllung eben dieser durch das Child-Template.

Gegeben sei mal folgendes Dummy-Beispiel:

layout.php
PHP:
<!DOCTYPE html>
<html lang="de">
    <head>
        <meta charset="utf-8">
        <title><?php block('title'); ?><?php endblock(); ?></title>
    </head>
    <body>
         <?php block('content'); ?>
         <?php endblock(); ?>
    </body>
</html>

child.php
PHP:
<?php layout('layout.php'); ?>
<?php block('title'); ?> Ein Seitentitel <?php endblock(); ?>
<?php block('content'); ?>
<p>Lorem ipsum dolor sit amet...</p>
<?php endblock(); ?>

Meine bisherige Vorgehensweise ist es, dass ich zunächst die child.php in den Output-Buffer lade. Soweit ich das aus meinen Recherchen herleiten konnte, wird für jeden Aufruf der block()-Funktion ein weiterer Output-Buffer aufgemacht und bei Aufruf von endblock() wieder geschlossen. Bei den Definierungen der Blöcke in der layout.php dürfte ja nichts weiter in den Output-Buffer wandern, aber der erstellte Block muss zumindest irgendwo festgehalten werden. Soweit ich das aus ein paar Quellcodes rauslesen konnte, passiert das in einem simplem Array. In der child.php hingegen wird etwas in den Puffer geschrieben, dessen Inhalt ich dann anhand des Namens des Blocks wieder an die korrekte Stelle im Block-Array schreiben kann.

So weit, so gut. Ich habe die definierten Blöcke, sowie die dazugehörigen Inhalte erfasst. Nur wie bekomme ich jetzt die ursprünglichen PHP-Befehle aus der layout.php wieder entfernt und durch die Inhalte ersetzt?

In einem Quellcode habe ich ein recht wildes Konstrukt mit substr() gesehen, welches in einer Callback-Funktion für ob_start() mit drinne hing und zuvor zusätzlich noch der Anfang und Ende eines Blocks mitgespeichert wurden. Sah irgendwie unsauber und ziemlich nach Brechstangen-Art gelöst aus. Deshalb bin ich mir nicht sicher, ob ein rumdoktern mittels diverser Befehle am Inhalt des Ausgabepuffers innerhalb des ob_start()-Callbacks der Weisheit letzter Schluss sein kann. Was eleganteres fällt mir aber im Moment auch nicht unbedingt ein.

Habt ihr vielleicht ne Idee wie sich das lösen lässt?

Es wäre natürlich die einfachere Variante die Definition des Layouts in der child.php einfach an's Ende der Datei zu setzen, aber das gefällt mir von der Logik her nicht so ganz. Erst das Layout und dann die Inhalte wäre wünschenswerter.

Ich bin gespannt auf euren Input zu dem Thema.

Grüße
 
Werbung:
Moin Moin

Vorab: Ich bin mir dessen bewusst, dass fertige Templating Engines wie Blade oder Twig jenes im Titel erwähnte Feature bieten und setze seit 4 Jahren freudig Blade ein. Ich bin aber nicht auf der Suche nach einer Fertiglösung, sondern will die Funktionsweise dahinter verstehen und dies mit Vanilla-PHP mal nachvollziehen.

In den letzten Tagen habe ich diverse Artikel darüber gelesen und mich durch einige Quellcodes auf GitHub gewühlt, aber *Klick* hat's noch nicht gemacht. Konkret geht's um Definierung von Blöcken im Master-Template und die Auffüllung eben dieser durch das Child-Template.

Gegeben sei mal folgendes Dummy-Beispiel:

layout.php
PHP:
<!DOCTYPE html>
<html lang="de">
    <head>
        <meta charset="utf-8">
        <title><?php block('title'); ?><?php endblock(); ?></title>
    </head>
    <body>
         <?php block('content'); ?>
         <?php endblock(); ?>
    </body>
</html>

child.php
PHP:
<?php layout('layout.php'); ?>
<?php block('title'); ?> Ein Seitentitel <?php endblock(); ?>
<?php block('content'); ?>
<p>Lorem ipsum dolor sit amet...</p>
<?php endblock(); ?>

Meine bisherige Vorgehensweise ist es, dass ich zunächst die child.php in den Output-Buffer lade. Soweit ich das aus meinen Recherchen herleiten konnte, wird für jeden Aufruf der block()-Funktion ein weiterer Output-Buffer aufgemacht und bei Aufruf von endblock() wieder geschlossen. Bei den Definierungen der Blöcke in der layout.php dürfte ja nichts weiter in den Output-Buffer wandern, aber der erstellte Block muss zumindest irgendwo festgehalten werden. Soweit ich das aus ein paar Quellcodes rauslesen konnte, passiert das in einem simplem Array. In der child.php hingegen wird etwas in den Puffer geschrieben, dessen Inhalt ich dann anhand des Namens des Blocks wieder an die korrekte Stelle im Block-Array schreiben kann.

So weit, so gut. Ich habe die definierten Blöcke, sowie die dazugehörigen Inhalte erfasst. Nur wie bekomme ich jetzt die ursprünglichen PHP-Befehle aus der layout.php wieder entfernt und durch die Inhalte ersetzt?

In einem Quellcode habe ich ein recht wildes Konstrukt mit substr() gesehen, welches in einer Callback-Funktion für ob_start() mit drinne hing und zuvor zusätzlich noch der Anfang und Ende eines Blocks mitgespeichert wurden. Sah irgendwie unsauber und ziemlich nach Brechstangen-Art gelöst aus. Deshalb bin ich mir nicht sicher, ob ein rumdoktern mittels diverser Befehle am Inhalt des Ausgabepuffers innerhalb des ob_start()-Callbacks der Weisheit letzter Schluss sein kann. Was eleganteres fällt mir aber im Moment auch nicht unbedingt ein.

Habt ihr vielleicht ne Idee wie sich das lösen lässt?

Es wäre natürlich die einfachere Variante die Definition des Layouts in der child.php einfach an's Ende der Datei zu setzen, aber das gefällt mir von der Logik her nicht so ganz. Erst das Layout und dann die Inhalte wäre wünschenswerter.

Ich bin gespannt auf euren Input zu dem Thema.

Grüße

Endlich mal ein interessantes Thema :)

Habe mir mal den Twig Cache eines Projekts angesehen.
Bei Twig wird jedes Template in eine PHP Klasse kompiliert welche dann für jeden Block eine Methode block_* besitzt und einen $context Parameter akzeptiert. In dieser Methode wird das fertige HTML des jeweiligen Blocks Anhand des Context ausgegeben.

Wenn nun das Child-Template einen Block des Parent-Template überschreibt, ruft Twig einfach die block_* Methode des Child-Templates auf, statt die des Parent. Dort kann dann wiederum via displayParentBlock der Parent-Block gerendert werden - falls nötig.

Ich denke das kompilieren in eine PHP Klasse / splitten der Blocks in einzelne Methoden ist der wichtigste Schritt um eine flexible Engine zu erstellen.

PHP selbst ist ja eigentlich bereits eine Template Engine. Daher kannst du mit prozeduralem Code mMn. auch nicht mehr viel rausholen.
 
Ich selber habe eine Klasse geschrieben die mit einer rekursiven Funktion alle Templates entsprechend der Platzhalter im Tamplate füllt. Das erste geladene Template stellt eine Art Master dar und alle Muster darin haben eine selbstorganisierende Vererbungstruktur, die ich unabhängig , vollflexibel im HTML-Code festlege.
 
Werbung:
Ich selber habe eine Klasse geschrieben die mit einer rekursiven Funktion alle Templates entsprechend der Platzhalter im Tamplate füllt. Das erste geladene Template stellt eine Art Master dar und alle Muster darin haben eine selbstorganisierende Vererbungstruktur, die ich unabhängig , vollflexibel im HTML-Code festlege.

Dass Parent Blocks ausgeführt werden, obwohl das Child Template diese eigentlich überschreibt, ist bei dir vermutlich aber auch der Fall?
 
Moin

Endlich mal ein interessantes Thema
Keine Ursache :)

Ich habe mich nochmal etwas mehr in Blade reingelesen. Dort wird die Syntax zum Aufruf des Parent dahingehend kompiliert, dass diese an's Ende des Child verfrachtet wird. Das Kompilat selber ist am Ende nichts weiter als eine einfache PHP-Datei, welche gleichermaßen als "Cache" für die Blade-Engine dient, damit die Syntax nicht nochmals geparsed werden muss. Darüber hinaus denke ich, dass eben diese Template-Syntax solche Freiheiten beim Kompilieren in etwas Verwertbares erlaubt, aber eigentlich wollte ich keine eigene Syntax dazu basteln...

Mal sehen ob mir dazu noch was anderes einfällt.

PHP selbst ist ja eigentlich bereits eine Template Engine. Daher kannst du mit prozeduralem Code mMn. auch nicht mehr viel rausholen.

Die prozeduralen Aufrufe sind in Bezug auf den geposteten Code auch nur als Dummy gedacht bzw. in meinem Experimentier-Konstrukt sind diese als Aliase vorhanden, welche zum Zugriff auf Klassen-Instanzen diesen, welche bereits in einem IoC-Container vorhanden sind.

Gruß
 
Zurück
Oben