Как стать автором
Поиск
Написать публикацию
Обновить

Реализация паттерна Компоновщик (Composite pattern) на php

Время на прочтение3 мин
Количество просмотров8.3K

Введение


На определенной стадии изучения серверного программирования мне захотелось написать свой простенький фреймворк. Я рассчитывал, что это поможет более глубоко понять идеологию MVC и Zend Framework в частности. Когда дело дошло до части представления и генерации html я вспомнил о паттерне Компоновщик (Composite pattern). Возможно я несколько исказил его применение, но мысль пошла оттуда.

К сути


Любая страница состоит из объектов, которые так-же могут состоять из объектов. Этакая вложенность наталкивает на мысль рекурсивной генерации html-кода. Так же хочется иметь возможность дополнять содержимое любой части страницы в любой момент исполнения логики приложения и генерировать весь html-код разом.

К делу


Любой объект может содержать другой объект и т.д. Каждый объект обладает методом draw(), который отображает html-код своего объекта и вызывает метод draw() для всех дочерних объектов. Объекты могут быть разных типов (например: статья, список, пост, фотоальбом, шапка в конце концов). Конечно реализация метода draw() для каждого типа объектов будет своя. Хотелось бы выразить выше написанное кодом.

abstract class AbstractView {
    
    public $fillings;
    
    abstract public function draw();

    protected function insert($filling_name){
        if(isset($this->fillings[$filling_name])){
            $this->fillings[$filling_name]->draw();
        }
    } 

}

Метод insert() — метод, с помощью которого в методе draw() будут вызываться методы draw() дочерних объектов. Все дочерние объекты содержатся в ассоциативном массиве $fillings. Часто необходимо не генерировать html-код, а просто написать текст или число. Можно конечно Для таких целей наследовать объект View, метод draw() которого будет просто выводить необходимое значение, указанное, например, в конструкторе или дополнительном свойстве. Но это крайне не удобно и будет усложнять процесс формирования страницы. Поэтому создадим второй ассоциативный массив для хранения таких значений и метод для их вывода.

abstract class AbstractView {
    
    public $fillings;
    
    public $values;
    
    abstract public function draw();

    protected function insert($filling_name){
        if(isset($this->fillings[$filling_name])){
            $this->fillings[$filling_name]->draw();
        }
    }

    protected function write($value_name){
        if(isset($this->values[$value_name])){
            echo $this->values[$value_name];
        }
    }
    
}

Теперь напишем два простейших наследника для демонстрации. Один будет представлять шапку, а второй приветствие.

class LayoutView extends AbstractView {
    
    public function draw(){
        include '/layout.phtml';
    }
    
}

class IndexView extends AbstractView{
    
    public function draw(){
        include '/index.phtml';
    }
    
}

Что же такое файлы layout.phtml и index.phtml?
layout.phtml:
<!DOCTYPE html>
<html>
    <head>
        <title><?php $this->write('title')?></title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    </head>
    <body>
        <?php $this->insert('content'); ?>
    </body>
</html>

index.phtml:
<div>Hello, Habrahabr!</div>

Соединим все и с генерируем страницу:

$page = new LayoutView();
$page->values['title'] = "greating";
$page->fillings['content'] = new IndexView();
$page->draw();

Результат:

<!DOCTYPE html>
<html>
    <head>
        <title>greating</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    </head>
    <body>
        <div>Hello, Habrahabr!</div>
    </body>
</html>

На данный момент такая реализация кажется мне удобной, но не исключено, что в скором времени я изменю свое мнение.

Как сказал Вольтер:
«Я могу быть не согласным с Вашим мнением, но я готов отдать жизнь за Ваше право высказывать его.»

P.S.: Прошу обратить внимание на комментарии sdevalex о классе VariableView и arturgspb о типовой безопасности.
Теги:
Хабы:
Всего голосов 24: ↑16 и ↓8+8
Комментарии29

Публикации

Ближайшие события