MVC и PHP, часть 2
Добро пожаловать! Это вторая часть цикла статей, касающегося использования MVC в PHP-приложениях, в которой мы обсудим некоторые вопросы, возникающие в связи выше обозначенной темой.
Если вы не читали первую статью из данного цикла, то настоятельно рекомендуется начать чтение именно с нее, чтобы полностью быть в курсе дела. Итак, начнем!
Перенаправление и URL-адреса
Хотя теоретически MVC должна работать независимо от языка программирования, подружить её с PHP может оказаться непросто.
Первая проблема касается перенаправления URL-адресов. Этот аспект не продумывался при создании схемы MVC, вследствие чего, этот вопрос стал вставать очень остро.
Какие возможности мы имеем для решения проблемы переадресации? Первое, что можно попытаться сделать, это заранее записать все URL-адреса вашего сайта в специальное хранилище, вместе с информацией о том, какие модель, представление и контроллер будут загружены для каждой страницы или её части.
В этом случае, система берет запрошенный пользователем URL-адрес и загружает компоненты, привязанные к данной странице.
Этот способ подходит, если вы создаете, к примеру, сайт-портфолио со статическими адресами (но не динамическими):
<?php
$page = $_GET['page'];
if (!empty($page)) {
$data = array(
'about' => array('model' => 'AboutModel', 'view' => 'AboutView', 'controller' => 'AboutController'),
'portfolio' => array('model' => 'PortfolioModel', 'view' => 'PortfolioView', 'controller' => 'PortfolioController')
);
foreach($data as $key => $components){
if ($page == $key) {
$model = $components['model'];
$view = $components['view'];
$controller = $components['controller'];
break;
}
}
if (isset($model)) {
$m = new $model();
$c = new $controller($model);
$v = new $view($model);
echo $v->output();
}
}
Теперь, наши URL-адреса будут выглядеть так:
example.com/index.php?page=about
либо
example.com/index.php?page=portfolio
Приведенный выше пример MVC-системы, загружает модель, представление и контроллер, указанные для запрошенной страницы. Если параметр имеет значение «about», то будет отображена страница About. Если параметр имеет значение «portfolio», то, соответственно, будет загружена страница Portfolio.
Как мы можем видеть, даже у этого простого примера статического перенаправления, есть недостатки. Один из самых очевидных из них, это проблемы с масштабируемостью при расширении сайта, так как все ссылки жестко «зашиты» в массив.
Другим способом решения нашей задачи является создание классов модели, представления и контроллера, позволив им формировать значения параметров URL-адреса.
В примере со статической переадресацией, мы просто вытаскивали значения из массива и возвращали их в качестве параметров при загрузке страниц. Удаление данного массива позволит нам реализовать динамическую переадресацию.
Несмотря на то, что мы вынимаем значения из заранее сформированного массива, отношения между классами уже настроены.
При наличии фиксированного массива, мы не можем динамически переназначать параметры. Но зачем нам вообще может понадобиться это делать?
Ответ прост: в таком случае нам не нужно будет заполнять вручную массив всеми возможными ссылками, имеющимися на сайте.
Мы можем создавать страницы или их части с помощью модели, представления и контроллера.
Например:
<?php
$model = $_GET['model'];
$view = $_GET['view'];
$controller = $_GET['controller'];
$action = $_GET['action'];
if (!(empty($model) || empty($view) || empty($controller) || empty($action))) {
$m = new $model();
$c = new $controller($m, $action);
$v = new $view($m);
echo $v->output();
}
Теперь наши ссылки будут выглядеть так:
example.com/index.php?controller=controllername&model=modelname&view=viewname&action=actionname
Параметр «action» говорит системе, какую функцию контроллера нужно запустить. Важно помнить, что когда эта функция передает данные в модель, то вместе с ними передается информация о том, какое представление и действие нужно загрузить.
Это может быть, опять же, значение переменной «action», или отдельные данные, либо данные, сохраненные контроллером. Никогда не позволяйте контроллеру загружать или напрямую передавать данные представлению. Эти два компонента должны взаимодействовать только через модель и действия пользователя.
Оба подхода имеют свои преимущества и недостатки: статическое перенаправление работает более стабильно, быстрее в реализации и предоставляет разработчику больший контроль над системой, в то время как динамическое перенаправление позволяет создавать более сложные системы, где имеется потенциальная возможность расширения и усложнения.
Динамическое перенаправление позволяет возложить всю ответственность на контроллер, чего нельзя сделать при статическом перенаправлении, которое рассматривается как альтернатива традиционной схеме MVC. Тем не менее, при корректной и эффективной реализации динамическая маршрутизация в большинстве случаев более предпочтительна, чем статическая.
Добавление фронт-контроллера позволит вашей системе динамически загружать секции, в зависимости от того, что нужно показать. Человек по имени Alejandro Gervasio написал потрясающую статью в двух частях о шаблоне фронт-контроллера (the Front Controller pattern), которая затрагивает вопросы использования фронт-контроллера в MVC-приложении.
DRY (Don’t Repeat Yourself – принцип программирования «не повторяй сам себя») и шаблоны
Одним из аргументов «за» использование MVC, является общее улучшение организации вашего проекта, насколько это возможно.
Также, это позволяет свести к минимуму возможное повторное использование ранее написанного кода. Любой разработчик согласится, что худшее, что можно обнаружить в любом проекте, это повторение кода. Техника и целая философия, призванная сохранить читаемость кода и позволить повторно использовать компоненты, известна под названием DRY (Don’t Repeat Yourself) – «Не повторяй сам себя».
Принцип DRY говорит, что «каждый кусочек знания должен иметь единственное, однозначное и авторитетное представление внутри системы». Цель DRY состоит в том, чтобы дать разработчику все возможности для создания максимально динамичных и оптимизированных систем.
DRY также подразумевает, что если вам необходимо использовать один и тот же кусок кода в разных местах, то необходимо оформить его в виде метода и вызывать его при необходимости. Это позволяет оптимизировать работу системы и предоставляет возможность кэширования внутри системы для повышения общей производительности.
Корректная реализация этого принципа также означает, что изменение какого-либо элемента не влияет на работу других, не связанных с ним элементов, что делает DRY очень важным при разработке MVC-приложений.
Шаблоны
Слово «шаблон» может вызвать некоторые вопрос при попытке понимания его сути для тех, кто ранее сталкивался с веб-фреймворками на основе MVC, потому как большинство людей подразумевает под этим только представление.
Такое понимание неправильно, если вы хотите придерживаться традиционной схемы MVC. В идеале, вы будете иметь представление, которое взаимодействует с моделью при передаче и обработке данных, после того, как они были помещены в эту самую модель.
Затем, представление выбирает шаблон и передает в него полученные данные. Теперь, все готово для отображения с использованием блочной разметки, или с использованием операторов PHP: echo, print и подобных.
Независимо от выбранного метода, самое важное помнить, что данные должны быть в состоянии готовности к выводу через шаблон. Если вы обрабатываете данные непосредственно в шаблоне, то вероятно, что схема MVC вами реализована неправильно.
Ниже дан простой пример загрузки шаблона и передачи в него данных:
<?php
class Model
{
public $tstring;
public function __construct(){
$this->tstring = "Эта строка была загружена через шаблон.";
$this->template = "tpl/template.php";
}
}
<?php
class View
{
private $model;
public function __construct($model) {
$this->controller = $controller;
$this->model = $model;
}
public function output(){
$data = "<p>" . $this->model->tstring ."</p>";
require_once($this->model->template);
}
}
<!DOCTYPE html>
<html>
<head>
<meta charset="charset=utf-8">
<title>The Template name</title>
</head>
<body>
<h1><?php echo $data; ?></h1>
</body>
</html>
В дополнение к этому, шаблон пропускается через модель. Это позволяет динамически выбирать шаблон в зависимости от назначения той или иной модели.
Этот метод позволяет эффективно и беспрепятственно расширять MVC-систему, разделив разработку интерфейсной и внутренней частей приложения, что как раз и является истинной целью MVC-подхода.
Заключение
Схема MVC, только появившись, создала почву для бесконечных дебатов на тему интерпретации и реализации этой концепции в конкретных приложениях.
Споры становятся все более интенсивными по мере роста популярности использования PHP для создания веб-приложений. Это хороший знак, который указывает на подключение все большего количества разработчиков, которые желают усовершенствовать подход в программировании на PHP.
Использование MVC является очень предпочтительным, так как поощряет разделение разработки на независимые ветви, иначе говоря, позволяет отделить разработку фронт-энда от разработки бэк-энда.
Всем тем, кто пока еще не вкусил мощи и потенциала MVC, очень рекомендую срочно взять себе на вооружение эту технологию. Уверяю, вы не будете разочарованы.