Вот подход, который я использую при создании сайтов на PHP с использованием шаблона MVC / разделения интересов:
Каркас, который я использую, состоит из трех основных частей:
- Модели - PHP классы. Я добавляю к ним методы для извлечения и сохранения данных. каждый
Модель представляет собой отдельный тип объекта в системе: пользователи, страницы,
сообщения в блоге
- Просмотров - шаблоны Smarty. Здесь живет HTML.
- Контроллеры - классы PHP. Это мозги приложения. типично
URL-адреса на сайте вызывают методы класса. example.com/user/show/1 будет
вызовите метод $ user_controller-> show (1). Контроллер извлекает данные
модели и дает его на вид.
У каждой из этих частей есть определенная работа или «забота». Задача model - обеспечить чистый интерфейс для данных. Обычно данные сайта хранятся в базе данных SQL. Я добавляю в модель методы для извлечения и сохранения данных.
Задачей view является отображение данных. Вся разметка HTML идет в представлении. Логика для обработки зебры для таблицы данных идет в представлении. Код для обработки формата, в котором должна отображаться дата, отображается в представлении. Мне нравится использовать шаблоны Smarty для представлений, потому что он предлагает несколько приятных функций для обработки подобных вещей.
Контроллер выполняет роль посредника между пользователем, моделью и представлением.
Давайте рассмотрим пример того, как они объединяются и в чем преимущества:
Представьте себе простой блог-сайт. Основной частью данных является пост. Также представьте, что сайт отслеживает количество просмотров поста. Для этого мы создадим таблицу SQL:
posts
id date_created title body hits
Теперь предположим, что вы хотите показать 5 самых популярных сообщений. Вот что вы можете увидеть в приложении, отличном от MVC:
$sql = "SELECT * FROM posts ORDER BY hits DESC LIMIT 5";
$result = mysql_query($sql);
while ($row = mysql_fetch_assoc($result)) {
echo "<a href="post.php?id=$row['id']">$row['title']</a><br />";
}
Этот фрагмент довольно прост и хорошо работает, если:
- Это единственное место, где вы хотите показать самые популярные сообщения
- Вы никогда не захотите изменить то, как это выглядит
- Вы никогда не решите изменить «популярный пост»
Представьте, что вы хотите показать 10 самых популярных постов на главной странице и 5 самых популярных в боковой панели на подстраницах. Теперь вам нужно либо скопировать приведенный выше код, либо поместить его во включаемый файл с логикой, чтобы проверить, где он отображается.
Что если вы хотите обновить разметку для домашней страницы, чтобы добавить класс "new-post" к сообщениям, которые были созданы сегодня?
Предположим, вы решили, что публикация популярна, потому что в ней много комментариев, а не хитов. База данных изменится, чтобы отразить это. Теперь каждое место в вашем приложении, которое показывает популярные сообщения, должно быть обновлено, чтобы отразить новую логику.
Вы начинаете видеть снежный ком сложной формы. Легко понять, как все сложнее поддерживать в ходе проекта. Также учтите сложность, когда над проектом работают несколько разработчиков. Должен ли проектировщик консультироваться с разработчиком базы данных при добавлении класса в вывод?
Использование подхода MVC и принудительное разделение проблем в вашем приложении могут смягчить эти проблемы. В идеале мы хотим разделить его на три области:
- логика данных
- логика приложения
- и отображение логики
Давайте посмотрим, как это сделать:
Начнем с модели . У нас будет класс $post_model
, и мы дадим ему метод с именем get_popular()
. Этот метод вернет массив сообщений. Дополнительно мы дадим ему параметр для указания количества возвращаемых сообщений:
post_model.php
class post_model {
public function get_popular($number) {
$sql = "SELECT * FROM posts ORDER BY hits DESC LIMIT $number";
$result = mysql_query($sql);
while($row = mysql_fetch_assoc($result)) {
$array[] = $row;
}
return $array;
}
}
Теперь для домашней страницы у нас есть контроллер , мы назовем его «home». Давайте представим, что у нас есть схема маршрутизации URL, которая вызывает наш контроллер при запросе домашней страницы. Задача состоит в том, чтобы получить популярные сообщения и дать им правильный вид:
home_controller.php
class home_controller {
$post_model = new post_model();
$popular_posts = $post_model->get_popular(10);
// This is the smarty syntax for assigning data and displaying
// a template. The important concept is that we are handing over the
// array of popular posts to a template file which will use them
// to generate an html page
$smarty->assign('posts', $popular_posts);
$smarty->view('homepage.tpl');
}
Теперь давайте посмотрим, как будет выглядеть :
homepage.tpl
{include file="header.tpl"}
// This loops through the posts we assigned in the controller
{foreach from='posts' item='post'}
<a href="post.php?id={$post.id}">{$post.title}</a>
{/foreach}
{include file="footer.tpl"}
Теперь у нас есть основные части нашего приложения, и мы можем видеть разделение задач.
модель связана с получением данных. Он знает о базе данных, он знает о SQL-запросах и операторах LIMIT. Он знает, что должен вернуть хороший массив.
Контроллер знает о запросе пользователя, что он просматривает домашнюю страницу. Он знает, что на главной странице должно отображаться 10 популярных сообщений. Он получает данные из модели и передает их в представление.
Представление знает, что массив сообщений должен отображаться в виде серии ахорных тегов с тегами разрыва после них. Он знает, что пост имеет заголовок и идентификатор. Он знает, что заголовок сообщения должен использоваться для якорного текста и что идентификатор сообщения должен использоваться в href. Представление также знает, что на странице должен быть верхний и нижний колонтитулы.
Также важно упомянуть то, чего не знает каждая часть .
Модель не знает, что популярные сообщения отображаются на главной странице.
Контроллер и представление не знают, что сообщения хранятся в базе данных SQL.
Контроллер и модель не знают, что после каждой ссылки на сообщение на главной странице должен быть тег разрыва.
Итак, в этом состоянии мы установили четкое разделение проблем между логикой данных (модель), логикой приложения (контроллер) и логикой отображения (представление). Что теперь? Мы взяли короткий простой фрагмент PHP и разбили его на три непонятных файла. Что это нам дает?
Давайте посмотрим, как разделение интересов может помочь нам в решении проблем, упомянутых выше. Чтобы повторить, мы хотим:
- Показывать популярные сообщения в боковой панели на подстраницах
- Подсветка новых сообщений с дополнительным классом CSS
- Изменить базовое определение "популярного сообщения"
Чтобы показать популярные сообщения на боковой панели, мы добавим два файла нашей подстраницы:
Контроллер подстраниц ... ... 1128 *
subpage_controller.php
class subpage_controller {
$post_model = new post_model();
$popular_posts = $post_model->get_popular(5);
$smarty->assign('posts', $popular_posts);
$smarty->view('subpage.tpl');
}
... и шаблон подстраницы:
subpage.tpl
{include file="header.tpl"}
<div id="sidebar">
{foreach from='posts' item='post'}
<a href="post.php?id={$post.id}">{$post.title}</a>
{/foreach}
</div>
{include file="footer.tpl"}
Новая подстраница контроллер знает, что на подстранице должны отображаться только 5 популярных сообщений. Подстраница view знает, что подстраницы должны помещать список сообщений в div боковой панели.
Теперь на главной странице мы хотим выделить новые сообщения. Мы можем достичь этого, изменив homepage.tpl.
{include file="header.tpl"}
{foreach from='posts' item='post'}
{if $post.date_created == $smarty.now}
<a class="new-post" href="post.php?id={$post.id}">{$post.title}</a>
{else}
<a href="post.php?id={$post.id}">{$post.title}</a>
{/if}
{/foreach}
{include file="footer.tpl"}
Здесь view обрабатывает всю новую логику для отображения популярных сообщений. контроллер и модель не должны были ничего знать об этом изменении. Это чисто дисплейная логика. Список подстраниц продолжает отображаться, как и раньше.
Наконец, мы бы хотели изменить популярный пост. Вместо того, чтобы основываться на количестве просмотров страницы, мы хотели бы, чтобы она основывалась на количестве комментариев, полученных постом. Мы можем применить это изменение к модели:
post_model.php
class post_model {
public function get_popular($number) {
$sql = "SELECT * , COUNT(comments.id) as comment_count
FROM posts
INNER JOIN comments ON comments.post_id = posts.id
ORDER BY comment_count DESC
LIMIT $number";
$result = mysql_query($sql);
while($row = mysql_fetch_assoc($result)) {
$array[] = $row;
}
return $array;
}
}
Мы увеличили сложность логики «популярного поста». Однако, как только мы внесли это изменение в модель , в одном месте новая логика применяется повсеместно. На главной странице и подстранице, без каких-либо изменений, теперь будут отображаться популярные сообщения на основе комментариев. Наш дизайнер не должен был быть вовлечен в это. На разметку это не влияет.
Надеемся, что это убедительный пример того, как разделение забот логики данных, логики приложения и логики отображения может облегчить разработку вашего приложения. Изменения в одной области, как правило, оказывают меньшее влияние на другие области.
Следование этому соглашению не волшебная пуля, которая автоматически сделает ваш код идеальным. И вы, несомненно, столкнетесь с проблемами, когда гораздо менее ясно, где должно быть разделение. В конце концов, все дело в управлении сложностью в приложении.
Вы должны много думать о том, как вы строите свои модели. Какие интерфейсы они предоставят (см. Ответ Грегори относительно контрактов)? С каким форматом данных контроллер и представление ожидают работать? Думая об этом заранее, будет легче в будущем.
Кроме того, при запуске проекта могут возникнуть некоторые накладные расходы, чтобы все эти части работали хорошо. Существует множество платформ, которые предоставляют строительные блоки для моделей, контроллеров, шаблонизаторов, маршрутизации URL и многого другого. Смотрите много других постов на SO для предложений по PHP MVC фреймворкам. Эти платформы помогут вам в работе, но вы, как разработчик, будете отвечать за управление сложностью и обеспечение разделения интересов.
Также отмечу, что приведенные выше фрагменты кода являются просто упрощенными примерами. Они могут (скорее всего) иметь ошибки. Однако они очень похожи по структуре на код, который я использую в своих проектах.