После авторизации Вы получите доступ к файлам, скрытым материалам сайта, исходным кодам
возможность комментировать и т.д.

Вы можете авторизоваться на сайте всего одним кликом:

2016-07-22
Основы PHP → Архитектура сайта (MVC)
Правильная архитектура сайта

В этом уроке я расскажу Вам, что такое архитектура сайта, какое у нее назначение и какой она бывает.

Что такое архитектура программы

Несмотря на то, что значение словосочетания "архитектура сайта" может быть вам интуитивно понятным, давайте попробуем изучить ряд определений, принадлежащих авторитетным источникам.

Архитектура — это базовая организация системы, воплощенная в ее компонентах, их отношениях между собой и с окружением, а также принципы, определяющие проектирование и развитие системы [IEEE 1471].

Архитектура программы или компьютерной системы — это структура или структуры системы, которые включают элементы программы, видимые извне свойства этих элементов и связи между ними [Басс (Bass)].

Архитектура — это структура организации и связанное с ней поведение системы. Архитектуру можно рекурсивно разобрать на части, взаимодействующие посредством интерфейсов, связи, которые соединяют части, и условия сборки частей. Части, которые взаимодействуют через интерфейсы, включают классы, компоненты и подсистемы [UML 1.5].

Архитектура программного обеспечения системы или набора систем состоит из всех важных проектных решений по поводу структур программы и взаимодействий между этими структурами, которые составляют системы. Проектные решения обеспечивают желаемый набор свойств, которые должна поддерживать система, чтобы быть успешной. Проектные решения предоставляют концептуальную основу для разработки системы, ее поддержки и обслуживания [McGovern (Мак-Говерн)].

Так что же такое архитектура программы?

Приведенные в предыдущем разделе определения слишком сухие для их восприятия неподготовленным читателем. Постараемся объяснить суть как можно проще.

Когда программа становится достаточно большой, программист разбивает ее на несколько файлов. Если не задумываться над выделением групп похожих функций и вынесением их в отдельные модули, такое разбиение принесет мало пользы. Код нельзя будет использовать повторно, в нем будет трудно ориентироваться. Программу будет сложно расширять и изменять.

Таким образом, назревает первый вопрос: как разбить программу на файлы. Файловая архитектура программы — это один из аспектов ее структуры.

Выделяя модули системы, необходимо понимать, в каком отношении друг к другу они будут находиться. Например, модули доступа к базе данных и обработки графических изображений вряд ли должны знать что-либо о существовании друг друга. Но модуль пользовательского интерфейса будет знать о них обоих (а они о нем не будут).

Отношения между компонентами системы также определяются ее архитектурой.

В целом, все значимые решения, направленные на организацию программы, а не на проблемы, решаемые с ее помощью, можно отнести к архитектуре.

Уровни абстракции

При проектировании модулей (выбора групп функций и распределения их по файлам в случае процедурного подхода) важно выделять абстракции и пытаться их разложить по нескольким уровням.

Модули низкого уровня максимально автономны, они не зависят от других частей программы. Хорошо спроектированные модули изолируют "внешний мир" от тонкостей решения поставленной перед ними задачи. Вызывающая сторона знает лишь интерфейс модуля (внешние функции), внутренняя часть для нее закрыта.

Рассмотрим в качестве примера галерею фотографий. Информация об изображениях и пользователях хранится в БД, пользовательский интерфейс разделен на клиентскую часть и панель администратора.

Структура программы могла бы быть такой, как на рисунке ниже:

В этом примере прослеживаются три уровня абстракции.

В любой программе, предназначенной для использования человеком, можно выделить, по крайней мере, два уровня: пользовательский интерфейс и модель. Модуль пользовательского интерфейса предназначен для представления и визуализации данных, обработки реакции пользователя. Модель заключает в себе логику решаемой задачи и не должна ни в коей мере быть зависимой от способа отображения данных. Модель должна быть легко переносима между разными типами пользовательского интерфейса.

Архитектура MVC

Сейчас популярен шаблон проектирования MVC. Он служит для отделения логики приложения от пользовательского интерфейса. Но сначала проясним, что такое шаблон проектирования.

Это набор типовых решений проектирования, каркас архитектуры или ее фрагмента. Если библиотека — это пакет повторно используемого кода, то шаблон проектирования — это пакет повторно используемых решений.

Что же предлагает нам MVC для отделения логики приложения от пользовательского интерфейса?

Шаблон MVC позволяет разделить данные, представление и обработку действий пользователя на три отдельных компонента:

  1. Модель (Model). Модель предоставляет данные (обычно для Представления), а также реагирует на запросы (обычно от Контроллера), изменяя свое состояние;
  2. Представление (View). Отвечает за отображение информации (пользовательский интерфейс);
  3. Контроллер (Controller). Интерпретирует данные, введенные пользователем, и информирует модель и представление о необходимости соответствующей реакции.

На рисунке ниже показаны отношения между компонентами каркаса. Проиллюстрируем рисунок небольшим примером.

Представьте форму, где можно ввести текст, нажать кнопку Edit и получить его транслитерацию:

Повторим шаги, изображенные на схеме:

  1. Пользователь нажимает кнопку Edit, при этом Представление (View) посылает сообщение Контроллеру (Controller): "Команда: edit"
  2. Контроллер принимает сообщение и обращается к Модели (Model), вызывая метод Edit() .
  3. В результате модель меняет свое состояние (запомненный в ней транслитерированный текст) и оповещает об этом представление: "Событие: changed".
  4. Представление принимает сигнал и обращается к модели за новым значением результата, вызывая ее метод Get() .

Реализация MVC

Реализация MVC предполагает объектно-ориентированный подход (ООП). Однако шаблон проектирования — это всего лишь набор решений. Адаптируем их для PHP без применения ООП. Упрощение делается для того, чтобы сконцентрироваться на сути разделения логики, а также для того, чтобы материал смог применить читатель, не знакомый с ООП.

Рассмотрим снова пример с галереей фотографий.
У нее есть два режима просмотра:

  1. Режим просмотра уменьшенных изображений (всех сразу);
  2. Режим просмотра фотографии полного размера (одной).

Также есть возможность загружать фотографии на сервер. Дополнительно реализуем поддержку типов визуализации, чтобы оценить гибкость каркаса.

На сайте будут две точки входа:

  1. index.php (просмотр галереи);
  2. photo.php (просмотр полноразмерной фотографии).
Эти два файла будем считать Контроллерами.

В качестве Модели будет выступать модуль, обеспечивающий работу с хранилищем изображений. Назовем его gallery.php и поместим в папку model.

В роли Представления будут выступать HTML-шаблоны, они будут находиться в папке templates. Что такое шаблоны и для чего они нужны — будет видно дальше.

Страницы просмотра галереи и просмотра фотографии будут иметь общую шапку и подвал страницы, отличаться будет только центральная часть.

Просмотр галереи будет иметь два типа визуализации:

  1. В виде таблицы (по умолчанию);
  2. В виде списка.
Нам потребуются четыре шаблона:
  1. main.php (каркас страницы);
  2. content_index_table.php (табличный вид содержимого галереи);
  3. content_index_list.php (списочный вид содержимого галереи);
  4. content_photo.php (содержимое страницы просмотра фотографии).

Получается следующая структура сайта:

Файловая структура разделена двумя горизонтальными чертами, образующими три секции. Файлы верхней секции относятся к Модели, файлы средней секции — к Представлению, файлы нижней секции — к Контроллеру.

Модель

Начнем с реализации Модели. В коде ниже приведен не полностью для минимизации и лучшей наглядности примера.

<?php
// Функция возвращает объект фотографии (ассоциативный массив).
function gallery_item($id)
{
   // Реализация пропущена,
   // тип результата — array
}

// Функция возвращает список фотографий.
function gallery_list()
{
   // Реализация пропущена,
   // тип результата — array
}

// Функция возвращает путь к уменьшенному изображению.
function gallery_icon($photo)
{
   // Реализация пропущена,
   // тип результата — string
}

// Функция возвращает путь к полноразмерному изображению.
function gallery_image($photo)
{
   // Реализация пропущена,
   // тип результата — string
}

// Функция добавляет в галерею новую фотографию.
function gallery_add($file_path, $file_name)
{
   // Реализация пропущена
}
?>

Мы определили лишь интерфейс Модели, оставив реализацию пропущенной. Однако для примера реализации каркаса MVC она вовсе и не нужна.

Представление

Теперь рассмотрим шаблоны. Начнем с общего каркаса страницы:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
   <meta content="text/html;charset=windows-1251"
   http-equiv="Content-Type">
   <title><?=$title?></title>
</head>
<body>
   <h1><?=$title?></h1>
   <?php include $content; ?>
</body>
</html>

Вас не должно смущать, что в шаблоне используются непонятно откуда взявшиеся переменные $title и $content . Их подставит Контроллер. Но об этом позже.

<?=$title?> — это сокращенный вариант записи <?php echo $title; ?>.

Его удобно использовать в шаблонах. Также в шаблонах удобнее использовать альтернативные варианты записи конструкций if-else , foreach , for , while . Выглядят они так:

if (<условие>):
   <тело>
endif;

foreach (<инициализация цикла>):
   <тело>
endforeach;

Остальные шаблоны будут подставляться в main.php таким образом:

<?php include $content; ?>

В примерах ниже, приведен их код:

Код templates/content_index_table.php

<b>Таблица</b> | <a href="index.php?view=list">Список</a>

<br/><br/>
<table>
   <tr>
   <?php $i = 0; ?>

      <?php foreach ($photos as $photo): ?>
         <?php if ($i % 3 == 2): ?>
      </tr><tr>
      <?php endif; ?>
      <td>
         <a href="photo.php?id=<?=$photo['id']?>">
            <img src="<?=gallery_icon($photo)?>" />
         </a>
      </td>
      <?php $i++; ?>

      <?php endforeach ?>
      </tr>
</table>

<br/><br/>

<form method="post" enctype="multipart/form-data">
   <input type="file" name="photo" />
   <br/>
   <input type="submit" value="Загрузить файл!" />
</form>

Код templates/content_index_list.php

<a href="index.php">Таблица</a> | <b>Список</b>

<br/><br/>

<?php foreach ($photos as $photo): ?>

   <a href="photo.php?id=<?=$photo['id']?>">
      <img src="<?=gallery_icon($photo)?>" />
   </a>
   <br/>

<?php endforeach ?>

<br/><br/>

<form method="post" enctype="multipart/form-data">
   <input type="file" name="photo" />
   <br/>
   <input type="submit" value="Загрузить файл!" />
</form>

templates/content_photo.php:
<a href="index.php">Назад</a>

<br/><br/>

<img src="<?=gallery_image($photo)?>" />

Контроллер

И, наконец, соберем все вместе, описав наши два Контроллера. Их задача заключается в обработке запроса, выборе шаблона и подстановке нужных шаблону данных. Данные берутся, как правило, из модели.

Контроллер галереи загружает фотографию, если пользователь отправил файл. Иначе он извлекает из модели список фотографий, выбирает нужный шаблон (в зависимости от желания пользователя) и выводит этот шаблон, передав ему список фотографий:

Код index.php

<?php
// Подключение библиотек.
require_once('model/gallery.php');

// Загружаем фотографию, если пользователь отправил файл.
if (isset($_FILES['photo']))
{
   gallery_add($_FILES['photo']['tmp_name'], $_FILES['photo']['name']);
   header('Locaton: index.php');
   exit();
}

// Подготовка данных.
$photos = gallery_list();

// Заголовок страницы.
$title = 'Галерея фотографий';

// Выбор шаблона содержимого.
$content = ($_GET['view'] == 'list')
   ? 'templates/content_index_list.php'
   : 'templates/content_index_table.php';

// Вывод HTML.
include 'templates/main.php';
?>

Контроллер просмотра фотографии еще проще:

Код photo.php

<?php
// Подключение библиотек.
require_once('model/gallery.php');

// Подготовка данных.
$photo = gallery_item($_GET['id']);

// Заголовок страницы.
$title = 'Просмотр фотографии';

// Выбор шаблона содержимого.
$content = 'templates/content_photo.php';

// Вывод HTML.
include 'templates/main.php';
?>

В заключение

Старайтесь уделять достаточно внимания разработке архитектуры вашего приложения. Если изначально создать прочный и расширяемый каркас, усилия окупятся сторицей.

Для реализации модели MVC лучше выбрать объектно-ориентированный подход.

Существует множество готовых решений каркаса, например в Zend Framework. Однако информации, изложенной в текущем уроке, достаточно для того, чтобы понять архитектурные решения MVC и начать их использовать уже сейчас.

2411
0
Пожалуйста, авторизируйтесь, чтобы скачать архив с файлами урока