<?php
$result = preg_replace_callback(..., array($this, 'replacement'), ...);
?>
Ik heb een voorbeeldje gemaakt van hoe je loops zou kunnen afhandelen. Hopelijk is het een goed voorbeeld:
Template.php
<?php
error_reporting(E_ALL);
class Template
{
private $template;
private $data_stack;
public function __construct($template)
{
$this->template = $template;
// SplStack is PHP 5.3.
// Voor PHP < 5.3, gebruik
http://phphulp.ikhoefgeen.nl/SplStack.phps
$this->data_stack = new SplStack();
}
public function apply($data)
{
return $this->parse($this->template, $data);
}
private function parse($template, $data)
{
// push data op de stack, zodat de replace-functies weten in welke data ze moeten zoeken voor het vervangen van variabelen.
$this->data_stack->push($data);
// parse alle blokken, recursief. Ieder blok komt weer door deze zelfde method heen.
$result = preg_replace_callback('{\{(\w+?)\}(.+?)\{/\\1\}}', array($this, 'parse_block'), $template);
// Werk van binnen naar buiten. Handel eerst de blokken af (hierboven) en dan pas de variabelen
$result = preg_replace_callback('{\{(\w+)\}(?!.*\{/\\1\})}', array($this, 'parse_placeholder'), $result);
// haal de verwijzing naar de data weer weg, zodat we in het omliggende blok weer bij de goeie data komen.
$this->data_stack->pop();
return $result;
}
private function parse_block($matches)
{
list(, $block_name, $block_code) = $matches;
$data = $this->data_stack->top();
$block_data = $data[$block_name];
$results = array();
foreach($block_data as $step_data)
{
$results[] = $this->parse($block_code, $step_data);
}
return implode($results);
}
private function parse_placeholder($matches)
{
list(, $placeholder_name) = $matches;
$data = $this->data_stack->top();
return $data[$placeholder_name];
}
}
// Dit is de meest onbegrijpelijke test-data ooit. Trust me.
$template = 'Hoi {block1} (begin-block1) {var_y} {block2} (begin-block2) {var_x} (eind-block2) {/block2} test2 (eind-block1) {/block1} Hoi2';
$data = array(
'block1' => array(
0 => array(
'var_y' => 'XXvar_y1XX',
'block2' => array(
0 => array('var_x' => 'XXvar_x11'),
1 => array('var_x' => 'XXvar_x12'),
2 => array('var_x' => 'XXvar_x13'),
)
),
1 => array(
'var_y' => 'XXvar_y2XX',
'block2' => array(
0 => array('var_x' => 'XXvar_x21'),
1 => array('var_x' => 'XXvar_x22'),
2 => array('var_x' => 'XXvar_x23'),
)
)
)
);
$x = new Template($template);
echo $x->apply($data);
?>
Kort samengevat, ik loop de code af op zoek naar {block} {/block}, en zodra ik dat vind, beschouw ik dat block als een nieuw template, met een eigen setje variabelen, en ga ik dat op dezelfde manier parsen. (Dus eerst weer de blokken daarin, en dan de variabelen daarin).
De stack is voor de callback-functies om bij te houden welke data ze moeten gebruiken. In andere programmeertalen kan je dat wel met closures doen (PHP 5.3 bijvoorbeeld ;) ) maar voor PHP moet het maar even zo. De stack is zeg maar een tijdelijke verwijzing naar $data, maar hij moet ook de voorgaande waarden van $data onthouden omdat de functie zichzelf binnen zichzelf aanroept.
(Die class maakt gebruik van een class genaamd SplStack, een class die alleen in PHP 5.3 zit. Gebruik je die niet, dan moet je even
SplStack.php includen.)
edit: code even hier geplakt.