Laminas ViewModel

Code
<?php

define('NL', PHP_EOL . PHP_EOL);

use Laminas\View\Renderer\PhpRenderer;
use Laminas\Escaper\Escaper;
use Laminas\View\Model\ViewModel;
use Laminas\View\Resolver\TemplatePathStack;
use Laminas\View\View;

// usually you escape template variables too
echo '- how the templates look like:' . NL;
$baseTemp = __DIR__ . '/templates/base.phtml';
$leftTemp = __DIR__ . '/templates/left.phtml';
$rightTemp = __DIR__ . '/templates/right.phtml';

$esc = new Escaper();
echo $esc->escapeHtml(file_get_contents($baseTemp)) . NL;
echo $esc->escapeHtml(file_get_contents($leftTemp)) . NL;
echo $esc->escapeHtml(file_get_contents($rightTemp)) . NL;

// ----- snippet for using ViewModel -----

$left = new ViewModel(array('value' => 'lefty'));
$left->setTemplate('left');

$right = new ViewModel(array('value' => 'righty'));
$right->setTemplate('right');

$base = new ViewModel();
$base->setTemplate('base');
// "has_parent" is important for rendering its children
$base->setOption('has_parent', true);

$base->addChild($left, 'left_td')
    ->addChild($right, 'right_td');

// ----- snippet for rendering -----

$func = function() {
    $resolver = new TemplatePathStack();
    $resolver->addPath(__DIR__ . '/templates');

    $renderer = new PhpRenderer();
    $renderer->setResolver($resolver);
    
    return $renderer;
};

$view = new View();
// expects callable, not one of the Laminas\View\Strategy
$view->addRenderingStrategy($func);
echo '- rendering the view models:' . NL;
echo $view->render($base);
Result
- how the templates look like:

<table border="1"><tr><td><?php echo $this->left_td ?></td><td><?php echo $this->right_td ?></td></tr></table>

<strong>left value: <?php echo $this->value ?></strong>

<em>right value: <?php echo $this->value ?></em>

- rendering the view models:

left value: leftyright value: righty
Used Versions
PHP 8.3, Laminas MVC 3.2, Symfony 5.2, Laravel 8.28, PHPUnit 9.5, Doctrine ORM 2.8