3v4l.org

run code in 300+ PHP versions simultaneously
<?php namespace RefactoringGuru\AbstractFactory\RealWorld; /** * Паттерн Абстрактная Фабрика * * Назначение: Предоставляет интерфейс для создания семейств связанных или * зависимых объектов, без привязки к их конкретным классам. * * Пример: В этом примере паттерн Абстрактная Фабрика предоставляет * инфраструктуру для создания нескольких разновидностей шаблонов для одних и * тех же элементов веб-страницы. * * Чтобы веб-приложение могло поддерживать сразу несколько разных движков * рендеринга страниц, его классы должны работать с шаблонами только через * интерфейсы, не привязываясь к конкретным классам. Чтобы этого достичь, * объекты приложения не должны создавать шаблоны напрямую, а поручать создание * специальным объектам-фабрикам, с которыми тоже надо работать через * абстрактный интерфейс. * * Благодаря этому, вы можете подать в приложение фабрику, соответствующую * одному из движков рендеринга, зная, что с этого момента, все шаблоны будут * порождаться именно этой фабрикой, и будут соответствовать движку рендеринга * этой фабрики. Если вы захотите сменить движок рендеринга, то всё что нужно * будет сделать — это подать в приложение объект фабрики другого типа и ничего * при этом не сломается. */ /** * Интерфейс Абстрактной фабрики объявляет создающие методы для каждого * определённого типа продукта. */ interface TemplateFactory { public function createTitleTemplate(): TitleTemplate; public function createPageTemplate(): PageTemplate; public function getRenderer(): TemplateRenderer; } /** * Каждая Конкретная Фабрика соответствует определённому варианту (или * семейству) продуктов. * * Эта Конкретная Фабрика создает шаблоны Twig. */ class TwigTemplateFactory implements TemplateFactory { public function createTitleTemplate(): TitleTemplate { return new TwigTitleTemplate(); } public function createPageTemplate(): PageTemplate { return new TwigPageTemplate($this->createTitleTemplate()); } public function getRenderer(): TemplateRenderer { return new TwigRenderer(); } } /** * А эта Конкретная Фабрика создает шаблоны PHPTemplate. */ class PHPTemplateFactory implements TemplateFactory { public function createTitleTemplate(): TitleTemplate { return new PHPTemplateTitleTemplate(); } public function createPageTemplate(): PageTemplate { return new PHPTemplatePageTemplate($this->createTitleTemplate()); } public function getRenderer(): TemplateRenderer { return new PHPTemplateRenderer(); } } /** * Каждый отдельный тип продукта должен иметь отдельный интерфейс. Все варианты * продукта должны соответствовать одному интерфейсу. * * Например, этот интерфейс Абстрактного Продукта описывает поведение шаблонов * заголовков страниц. */ interface TitleTemplate { public function getTemplateString(): string; } /** * Этот Конкретный Продукт предоставляет шаблоны заголовков страниц Twig. */ class TwigTitleTemplate implements TitleTemplate { public function getTemplateString(): string { return "<h1>{{ title }}</h1>"; } } /** * А этот Конкретный Продукт предоставляет шаблоны заголовков страниц * PHPTemplate. */ class PHPTemplateTitleTemplate implements TitleTemplate { public function getTemplateString(): string { return "<h1><?= \$title; ?></h1>"; } } /** * Это еще один тип Абстрактного Продукта, который описывает шаблоны целых * страниц. */ interface PageTemplate { public function getTemplateString(): string; } /** * Шаблон страниц использует под-шаблон заголовков, поэтому мы должны * предоставить способ установить объект для этого под-шаблона. Абстрактная * фабрика позаботится о том, чтобы подать сюда под-шаблон подходящего типа. */ abstract class BasePageTemplate implements PageTemplate { protected $titleTemplate; public function __construct(TitleTemplate $titleTemplate) { $this->titleTemplate = $titleTemplate; } } /** * Вариант шаблонов страниц Twig. */ class TwigPageTemplate extends BasePageTemplate { public function getTemplateString(): string { $renderedTitle = $this->titleTemplate->getTemplateString(); return <<<HTML <div class="page"> $renderedTitle <article class="content">{{ content }}</article> </div> HTML; } } /** * Вариант шаблонов страниц PHPTemplate. */ class PHPTemplatePageTemplate extends BasePageTemplate { public function getTemplateString(): string { $renderedTitle = $this->titleTemplate->getTemplateString(); return <<<HTML <div class="page"> $renderedTitle <article class="content"><?= \$content; ?></article> </div> HTML; } } /** * Классы отрисовки отвечают за преобразовании строк шаблонов в конечный HTML * код. Каждый такой класс устроен по-раному и ожидает на входе шаблоны только * своего типа. Работа с шаблонами через фабрику позволяет вам избавиться от * риска подать в отрисовщик шаблон не того типа. */ interface TemplateRenderer { public function render(string $templateString, array $arguments = []): string; } /** * Отрисовщик шаблонов Twig. */ class TwigRenderer implements TemplateRenderer { public function render(string $templateString, array $arguments = []): string { return \Twig::render($templateString, $arguments); } } /** * Отрисовщик шаблонов PHPTemplate. Оговорюсь, что эта реализация очень простая, * если не примитивная. В реальных проектах используйте `eval` с * осмотрительностью, т.к. неправильное использование этой функции может * привести к дырам безопасности. */ class PHPTemplateRenderer implements TemplateRenderer { public function render(string $templateString, array $arguments = []): string { extract($arguments); ob_start(); eval(' ?>' . $templateString . '<?php '); $result = ob_get_contents(); ob_end_clean(); return $result; } } /** * Клиентский код. Обратите внимание, что он принимает класс Абстрактной Фабрики * в качестве параметра, что позволяет клиенту работать с любым типом конкретной * фабрики. */ class Page { public $title; public $content; public function __construct($title, $content) { $this->title = $title; $this->content = $content; } // Вот как вы бы использовали этот шаблон в дальнейшем. Обратите внимание, // что класс страницы не зависит ни от классов шаблонов, ни от классов // отрисовки. public function render(TemplateFactory $factory): string { $pageTemplate = $factory->createPageTemplate(); $renderer = $factory->getRenderer(); return $renderer->render($pageTemplate->getTemplateString(), [ 'title' => $this->title, 'content' => $this->content ]); } } /** * Теперь в других частях приложения клиентский код может принимать фабричные * объекты любого типа. */ $page = new Page('Sample page', 'This it the body.'); echo "Testing actual rendering with the PHPTemplate factory:\n"; echo $page->render(new PHPTemplateFactory()); // Можете убрать комментарии, если у вас установлен Twig. // echo "Testing rendering with the Twig factory:\n"; echo $page->render(new // TwigTemplateFactory());

Here you find the average performance (time & memory) of each version. A grayed out version indicates it didn't complete successfully (based on exit-code).

VersionSystem time (s)User time (s)Memory (MiB)
8.1.70.0000.00817.43
8.1.60.0000.00817.64
8.1.50.0040.00417.54
8.1.40.0040.00417.55
8.1.30.0050.00317.72
8.1.20.0040.00417.63
8.1.10.0050.00317.50
8.1.00.0030.00517.45
8.0.200.0080.00017.02
8.0.190.0040.00417.11
8.0.180.0050.00316.96
8.0.170.0000.00817.04
8.0.160.0040.00416.96
8.0.150.0000.00717.00
8.0.140.0000.00716.90
8.0.130.0000.00613.36
8.0.120.0000.00816.95
8.0.110.0000.00817.04
8.0.100.0000.00716.80
8.0.90.0040.00417.08
8.0.80.0090.00917.01
8.0.70.0040.00417.02
8.0.60.0080.00017.00
8.0.50.0070.00017.07
8.0.30.0090.00516.89
8.0.20.0060.00917.06
8.0.10.0110.01517.18
8.0.00.0120.00317.11
7.4.300.0000.00616.70
7.4.290.0030.00316.65
7.4.280.0080.00016.55
7.4.270.0040.00416.56
7.4.260.0000.00513.36
7.4.250.0000.00816.58
7.4.240.0000.00716.58
7.4.230.0040.00416.55
7.4.220.0040.00316.48
7.4.210.0070.00716.56
7.4.200.0070.00016.66
7.4.160.0070.00716.63
7.4.150.0110.00316.47
7.4.140.0070.01016.42
7.4.130.0110.00416.59
7.4.120.0070.00716.57
7.4.110.0070.00716.46
7.4.100.0110.00616.64
7.4.90.0130.00316.52
7.4.80.0120.00316.54
7.4.70.0030.01016.55
7.4.60.0080.00816.54
7.4.50.0070.00716.31
7.4.40.0030.01016.46
7.4.30.0130.00716.62
7.4.20.0030.01116.59
7.4.10.0070.00716.58
7.4.00.0040.01116.59
7.3.330.0000.00716.36
7.3.320.0000.00513.25
7.3.310.0070.00016.35
7.3.300.0030.00316.50
7.3.290.0070.00916.49
7.3.280.0100.00316.44
7.3.270.0000.01416.42
7.3.260.0100.00716.53
7.3.250.0030.01116.42
7.3.240.0030.01016.38
7.3.230.0080.00516.49
7.3.220.0040.01116.35
7.3.210.0080.00516.38
7.3.200.0110.00816.27
7.3.190.0090.00616.42
7.3.180.0100.00716.33
7.3.170.0060.01016.26
7.3.160.0040.01116.37
7.3.150.0070.01116.40
7.3.140.0070.00716.37
7.3.130.0140.00716.33
7.3.120.0040.01116.34
7.3.110.0000.01416.41
7.3.100.0100.00316.36
7.3.90.0050.00916.67
7.3.80.0080.00816.48
7.3.70.0040.01216.38
7.3.60.0040.01116.38
7.3.50.0110.00416.46
7.3.40.0060.01316.49
7.3.30.0000.01616.46
7.3.20.0100.01616.50
7.3.10.0170.00616.39
7.3.00.0070.01716.41

preferences:
28.21 ms | 414 KiB | 15 Q