Flyweight design pattern is used to minimise memory usage by sharing as much memory as possible with same objects. It is like caching mechanism but no cache is involved. In this example we are going to render templates. If a template was rendered before we will get the previous version. The important point here is it wouldn't work with dynamic dataset. You have to make sure that the data returned is exactly what you would need.


Flowchart



Files


FlyweightController


declare(strict_types=1);

namespace App\Controller;

use App\Flyweight\Factory\TemplateRenderFactory;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Symfony\Component\Routing\Annotation\Route;

class FlyweightController
{
private $templateRenderFactory;

public function __construct(TemplateRenderFactory $templateRenderFactory)
{
$this->templateRenderFactory = $templateRenderFactory;
}

public function index()
{
$template1 = $this->templateRenderFactory->create('flyweight/home.txt.twig');
$template2 = $this->templateRenderFactory->create('flyweight/home.txt.twig');
$template3 = $this->templateRenderFactory->create('flyweight/contact.txt.twig');
$template4 = $this->templateRenderFactory->create('flyweight/contact.txt.twig');

$content1 = $template1->render();
$content2 = $template2->render();
$content3 = $template3->render();
$content4 = $template4->render();

print_r(
[
'template1_obj_id' => md5(spl_object_hash($template1)),
'content1' => $content1,
'template2_obj_id' => md5(spl_object_hash($template2)),
'content2' => $content2,
'template3_obj_id' => md5(spl_object_hash($template3)),
'content3' => $content3,
'template4_obj_id' => md5(spl_object_hash($template4)),
'content4' => $content4,
'count' => $this->templateRenderFactory->count(),
]
);
}
}

TemplateRenderFactory


declare(strict_types=1);

namespace App\Flyweight\Factory;

use App\Flyweight\TemplateRenderFlyweight;
use App\Flyweight\RenderFlyweightInterface;
use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface;

class TemplateRenderFactory
{
private $templating;
private $pool = [];

public function __construct(EngineInterface $templating)
{
$this->templating = $templating;
}

public function create(string $template): RenderFlyweightInterface
{
if (!isset($this->pool[$template])) {
$this->pool[$template] = new TemplateRenderFlyweight($this->templating, $template);
}

return $this->pool[$template];
}

public function count(): int
{
return count($this->pool);
}
}

RenderFlyweightInterface


declare(strict_types=1);

namespace App\Flyweight;

interface RenderFlyweightInterface
{
public function render(): string;
}

TemplateRenderFlyweight


declare(strict_types=1);

namespace App\Flyweight;

use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface;

class TemplateRenderFlyweight implements RenderFlyweightInterface
{
private $templating;
private $template;

public function __construct(EngineInterface $templating, string $template)
{
$this->templating = $templating;
$this->template = $template;
}

public function render(): string
{
return $this->templating->render($this->template);
}
}

home.txt.twig


Content of the "home" page.


contact.txt.twig


Content of the "contact" page.

Test


We requested two home and two contact pages. As you can see below, there has been only one copy of each page request instead of two.


Array
(
[template1_obj_id] => 9ccbdd93639d71e7787c557c54e5e3dc
[content1] => Content of the "home" page.

[template2_obj_id] => 9ccbdd93639d71e7787c557c54e5e3dc
[content2] => Content of the "home" page.

[template3_obj_id] => 1ac487dee09b2da4db43a0da55bccecb
[content3] => Content of the "contact" page.

[template4_obj_id] => 1ac487dee09b2da4db43a0da55bccecb
[content4] => Content of the "contact" page.

[count] => 2
)