[Что такое MVC? 】
MVC — это концепция, которая позволяет гармонично объединить «три части (а именно, полное имя MVC, Модель, Представление и Контроллер)» для формирования сложного приложения. Автомобиль — очень хороший пример MVC в реальной жизни. Когда мы смотрим на автомобиль, мы смотрим на две части вида (дисплея): интерьер и экстерьер. Оба они неотделимы от контроллера: драйвера. Тормозная система, рулевое колесо и другие системы управления представляют Модель: они берут методы управления от водителя (Контроллер) и применяют их к интерьеру и экстерьеру (Вид).
[MVC в Интернете]
Концепции, охватываемые инфраструктурой MVC, довольно просты и чрезвычайно гибки. Основная концепция заключается в том, что у вас есть один контроллер (например, index.php), который управляет всеми приложениями в рамках платформы, основанными на запросах параметров. Этот контроллер обычно содержит (как минимум) параметр, определяющий модель, событие и параметр GET. Таким образом, контроллер может подтверждать все запросы и запускать соответствующие события. Например, такой запрос /index.php?module=foo&event=bar, вероятно, используется для загрузки класса с именем foo, а затем запуска foo::bar()[который является функцией bar()]. Плюсы этого в том, что
поддерживать интерфейс для всех приложений,
сохраняя при этом бесчисленное количество кодов в приложении, очень хлопотно, поскольку каждый фрагмент кода имеет свой относительный путь, ссылку на базу данных, проверку и т. д. Это избавит вас от хлопот и позволит объединять и повторно использовать код.
[Зачем создавать собственную структуру MVC? 】
До сих пор я не видел многих фреймворков MVC, написанных на PHP. На самом деле я знаю только один — Solar, полностью написанный на PHP5. Другой — Cake, который пытается стать RoR (Ruby on Rails — сетевой инфраструктурой с открытым исходным кодом для языка Ruby) PHP. Я сам испытываю некоторое недовольство обоими фреймворками: они не используют преимущества существующего кода, включенного в PEAR, Smarty и т. д.; наконец, текущий Cake все еще относительно беспорядочен, Solar — это фреймворк, написанный в основном одним человеком; нет намерения сказать, что его автор, Пол, не является хорошим человеком или хорошим программистом). Эти вопросы, вероятно, не заставят вас отрицать их, и, скорее всего, они вас вообще не волнуют. Но из-за этого я прошу вас смотреть на них как можно чаще.
[Старый способ]
Если вы вернетесь в 2001 год и посмотрите на написанный вами код, то автор может найти файл с именем template.txt, который выглядит так: www.phpv.net Пожалуйста, укажите источник для перепечатки
<?php
require_once('config.php'); // Другие требования, информация о базе данных и т. д.
$APP_DB = 'mydb';
$APP_REQUIRE_LOGIN = false // Устанавливается в значение true, если скрипт требует входа в систему;
$APP_TEMPLATE_FILE = 'foo.php' // Smarty-шаблон;
$APP_TITLE = 'Мое приложение';
если ($APP_REQUIRE_LOGIN == true) {
if (!isset($_SESSION['userID'])) {
header("Местоположение: /путь/к/login.php");
Выход();
}
}
$db = DB::connect('mysql://'.$DB_USER.':'.$DB_PASS.'@localhost/'.$APP_DB);
if (!PEAR::isError($db)) {
$db->setFetchMode(DB_FETCHMODE_ASSOC);
} еще {
die($db->getMessage());
}
// Поместите сюда свою логику
// Выводим шаблон
include_once(APP_TEMPLATE_PATH.'/header.php');
include_once(APP_TEMPLATE_PATH.'/'.$APP_TEMPLATE_FILE);
include_once(APP_TEMPLATE_PATH.'/footer.php');
?>
О боже, просто глядя на этот код, я съеживаюсь. Концепция этого кода заключается в том, чтобы каждое приложение можно было адаптировать к этому методу обработки. Например, я могу просто скопировать файл template.txt в myapp.php, изменить несколько переменных, и вуаля, оно запустится. Тем не менее, этот высокоорганизованный подход имеет некоторые серьезные недостатки: что,
если мой начальник хочет, чтобы автор использовал myapp.php для вывода PDF в некоторых случаях, HTML в некоторых случаях и SOAP в некоторых случаях (запросы XML отправляются напрямую), что мне делать? делать?
Что делать, если этому приложению требуется аутентификация IMAP или LDAP?
Как обрабатывать различные типы кода (включая изменения, обновления и удаления)?
Как мне обрабатывать многоуровневую аутентификацию (администратор или неадминистратор)?
Как включить кэширование вывода? www.phpv.net Пожалуйста, укажите источник для перепечатки
[Новый способ]
Добавьте все в этот фреймворк MVC, и вы обнаружите, что жизнь так проста. Сравните следующий код:
<?php
класс myapp расширяет FR_Auth_User
{
публичная функция __construct()
{
родитель::__construct();
}
Публичная функция __default()
{
// Делаем что-нибудь здесь
}
Публичная функция delete()
{ }
публичная функция __destruct()
{
родитель::__destruct();
}
}
?>
Обратите внимание, что этот код явно не используется для связи с базой данных, определения того, вошел ли пользователь в систему или вывода какой-либо другой информации. В контроллере все это есть.
Если я хочу пройти аутентификацию в LDAP, я могу установить FR_Auth_LDAP. Контроллер может распознавать определенные методы вывода (например, $_GET['output']) и конвертировать их в PDF или SOAP в любое время. Обработчик событий delete отвечает только за удаление и не заботится ни о чем другом. Поскольку в этом модуле есть экземпляр класса FR_User, он может просто определить, вошел ли пользователь в систему и т. д. Smarty, как шаблонизатор, естественно управляет кешем, но контроллер также может управлять частью кеша.
Переход от старого способа, упомянутого ранее, к пути MVC может оказаться новой и незнакомой концепцией для многих людей, но как только вы переключитесь на такую концепцию, вернуться обратно будет довольно сложно.
[Построение нижнего слоя]
Я фанат PEAR, особенно класса PEAR_Error. PHP5 представляет новый встроенный класс «Exception», который заменяет PEAR_Error. Но у PEAR_Error есть несколько более практичных функций, чем у Exception. Поэтому примеры инфраструктуры MVC в этой серии статей будут использовать ее для обработки ошибок. В любом случае, мне все равно придется использовать Exception, чтобы получить ошибку от конструктора, поскольку они не могут сами передать ошибку.
Цель разработки этих базовых классов следующая:
Используйте PEAR для быстрого добавления функций в базовые классы
для создания небольших, многократно практичных абстрактных классов, чтобы пользователи могли быстро разрабатывать приложения в этой среде.
Используйте
phpDocumentor для создания документов для всех базовых классов.
иерархия классов будет выглядеть следующим образом:
- FR_Object будет обеспечивать базовую функциональность для использования всеми остальными объектами (включая ведение журнала, общий setFrom(), toArray())
- FR_Object_DB - это небольшой уровень, который обеспечивает ссылки на базу данных для подклассов и других функций
- FR_Module нижний класс всех приложений (также называемых модулями, моделями и т. д.)
– FR_Auth – это нижний класс всех механизмов проверки
· FR_Auth_User – это класс проверки, используемый для проверки всех модулей, которым необходимо проверить, вошел ли пользователь в систему
· FR_Auth_No все «поддельные классы проверки» для модулей, не требующих проверки.
FR_Presenter — базовый класс для всех приложений, которые обрабатывают загрузку и отображение.
— FR_Presenter_Smarty — уровень представления, включающий возможность загрузки различных дисков. Smarty — очень хороший шаблонный класс. Он имеет встроенный механизм кэширования и активную группу разработки (Примечание переводчика: это явно реклама~)
· FR_Presenter_debug — это уровень отображения части отладки. Опираясь на него, разработчики могут отлаживать приложения и отлаживать их
. FR_Presenter_rest — это уровень представления REST, который позволяет разработчикам выводить приложения в формате XML.
Из приведенной выше базовой структуры классов вы сможете увидеть различные части этой структуры MVC. FR_Module предоставляет все необходимое модулю, а FR_Presenter предоставляет различные методы отображения. В следующей статье этой серии я создам контроллер, который свяжет воедино все вышеперечисленные базовые классы.
[Стандарты кодирования]
Прежде чем официально писать код, вам следует сесть и обсудить (или подумать) стандарты кодирования со своими партнерами (или с самим собой). Общая идея программирования MVC вращается вокруг двух моментов: возможности повторного использования кода (уменьшения совпадений) и стандартизации кода. Я рекомендую принять во внимание как минимум следующие моменты:
Первое, что следует учитывать, — это стандарты именования переменных и сокращений. Не вступайте из-за этого в большую ссору с партнерами, но как только стандарты установлены, их необходимо соблюдать от начала до конца, особенно при написании низкоуровневого кода (базовых классов).
Настройте стандартный префикс для использования во всех функциях, классах и глобальных переменных. К сожалению, PHP не поддерживает «пространство имен (namespace)». Поэтому, чтобы избежать путаницы и конфликтов с именами переменных, разумно использовать префикс. В этой статье я буду использовать в качестве такого префикса «FR_».
[Написание нижнего слоя]
Планирование на уровне файлов очень важно. Базовое иерархическое планирование просто и несколько четко определено:
/
config.php
index.php
включает/
Авторизация.php
Авторизация/
№.php
Пользователь.php
Модуль.php
Объект.php
Объект/
БД.php
Презентер.php
Ведущий/
общий.php
debug.php
smarty.php
Умник/
модули/
пример/
config.php
пример.php
тпл/
пример.tpl
тпл/
по умолчанию/
кэш/
конфигурация/
шаблоны/
templates_c/
Вы можете подумать, что такая иерархия файлов должна представлять собой большой объем кода! Верно, но вы можете это сделать. К концу серии вы обнаружите, что ваше программирование станет проще, а скорость разработки значительно увеличится.
В иерархии файлов все базовые классы находятся в папке include. Каждый функциональный модуль использует файл конфигурации, по крайней мере, один файл модуля и один файл шаблона. Все модули содержатся в папке Modules. Я привык размещать файлы шаблонов в отдельной внешней папке — папке tpl.
config.php — центральный файл конфигурации, содержащий все глобальные переменные конфигурации.
index.php — Контроллер, подробно будет описан в следующей статье.
object.php — базовый класс для всех базовых классов, обеспечивающий большую часть функциональности, необходимой классу. FR_Object_DB наследует этот класс и предоставляет ссылки на базу данных.
Основная концепция структуры заключается в том, чтобы все подклассы наследовались от центрального класса, чтобы все они имели некоторые общие функции. В FR_Object можно поместить функцию привязки к базе данных, но не всем классам эта функция нужна, поэтому у FR_Object_DB есть причина существования, и о ней автор расскажет позже.
<?php
require_once('Log.php');
/**
*FR_Объект
*
* Базовый класс объектов для большинства классов, которые мы используем в нашей платформе.
* Обеспечивает базовую регистрацию и функциональность установки/получения.
*
* @author Джо Стамп < [email protected] >
* @packageFramework
*/
абстрактный класс FR_Object
{
/**
* $лог
*
* @var Mixed $log Экземпляр журнала PEAR
*/
protected $log;
/**
*$я
*
* @var смешанный $me Экземпляр ReflectionClass
*/
protected $me;
/**
* __конструкт
*
* @author Джо Стамп < [email protected] >
* @доступ к общедоступному
*/
публичная функция __construct()
{
$this->log = Log::factory('file',FR_LOG_FILE);
$this->me = новый ReflectionClass($this);
}
/**
* setFrom
*
* @author Джо Стамп < [email protected] >
* @доступ к общедоступному
* @param Mixed $data Массив переменных, которые можно присвоить экземпляру
* @return void
*/
публичная функция setFrom($data)
{
if (is_array($data) && count($data)) {
$valid = get_class_vars(get_class($this));
foreach ($действителен как $var => $val) {
если (isset($data[$var])) {
$this->$var = $data[$var];
}
}
}
}
/**
* toArray
*
* @author Джо Стамп < [email protected] >
* @доступ к общедоступному
* @return смешанный Массив переменных-членов, привязанных к имени переменной
*/
публичная функция toArray()
{
$defaults = $this->me->getDefaultProperties();
$возврат = массив();
foreach ($по умолчанию как $var => $val) {
if ($this->$var экземпляр FR_Object) {
$return[$var] = $this->$var->toArray();
} еще {
$return[$var] = $this->$var;
}
}
Возврат $возврат;
}
/**
* __разрушить
*
* @author Джо Стамп < [email protected] >
* @доступ к общедоступному
* @return void
*/
публичная функция __destruct()
{
if ($this->log instanceof Log) {
$this->log->close();
}
}
}
?>
auth.php – это базовый класс для всех функций аутентификации. Он является расширением FR_Module, и его основная функция — определить, как работает базовый класс проверки.
Так же, как и FR_Module, некоторые классы не требуют подключения к базе данных. Точно так же FR_Auth_No можно создавать и применять к классам, не требующим функций аутентификации.
<?php
абстрактный класс FR_Auth расширяет FR_Module
{
// {{{ __construct()
function__construct()
{
родитель::__construct();
}
// }}}
// {{{ аутентифицировать()
абстрактная функция аутентификации();
// }}}
// {{{ __destruct()
функция __destruct()
{
родитель::__destruct();
}
// }}}
}
?>
Module.php — сердце всех модулей
<?php
абстрактный класс FR_Module расширяет FR_Object_Web
{
// {{{ характеристики
/**
* $ведущий
*
* Используется в FR_Presenter::factory() для определения того, какая презентация (представление)
* для модуля следует использовать класс.
*
* @author Джо Стамп < [email protected] >
* @var строка $presenter
* @see FR_Presenter, FR_Presenter_common, FR_Presenter_smarty
*/
общественный $presenter = 'умный';
/**
* $данные
*
* Данные, установленные модулем, которые в конечном итоге будут переданы в представление.
*
* @author Джо Стамп < [email protected] >
* @var смешанные данные модуля $data
* @see FR_Module::set(), FR_Module::getData()
*/
protected $data = array();
/**;
* $имя
*
* @author Джо Стамп < [email protected] >
* @var string $name Имя класса модуля
*/
общедоступное $имя;
/**
* $tplFile
*
* @author Джо Стамп < [email protected] >
* @var string $tplFile Имя файла шаблона
* @see FR_Presenter_smarty
*/
общественный $tplFile
/**
* $имямодуля
*
* @author Джо Стамп < [email protected] >
* @var string $moduleName Имя запрошенного модуля
* @see FR_Presenter_smarty
*/
public $moduleName = null;
/**
* $pageTemplateFile
*
* @author Джо Стамп < [email protected] >
* @var string $pageTemplateFile Имя шаблона внешней страницы
*/
public $pageTemplateFile = null;
// }}}
// {{{ __construct()
/**
* __конструкт
*
* @author Джо Стамп < [email protected] >
*/
публичная функция __construct()
{
родитель::__construct();
$this->name = $this->me->getName();
$this->tplFile = $this->name.'.tpl';
}
// }}}
// {{{ __по умолчанию()
/**
* __по умолчанию
*
* Эта функция запускается контроллером, если событие не указано.
*по запросу пользователя.
*
* @author Джо Стамп < [email protected] >
*/
абстрактная публичная функция __default();
// }}}
// {{{ set($var,$val)
/**
* набор
*
* Установите данные для вашего модуля. В конечном итоге они будут переданы в модуль.
* класс презентатора через FR_Module::getData().
*
* @author Джо Стамп < [email protected] >
* @param string $var Имя переменной
* @param mix $val Значение переменной
* @return void
* @see FR_Module::getData()
*/
protected function set($var,$val) {
$this->data[$var] = $val;
}
// }}}
// {{{ getData()
/**
*getData
*
* Возвращает данные модуля.
*
* @author Джо Стамп < [email protected] >
* @return смешанный
* @see FR_Presenter_common
*/
публичная функция getData()
{
вернуть $this->данные;
}
// }}}
// {{{ isValid($module)
/**
*действителен
*
* Определяет, является ли $module допустимым модулем платформы. Он используется.
* контроллер, определяющий, подходит ли модуль к нашему фреймворку
* form. Если он распространяется как из FR_Module, так и из FR_Auth, то так и должно быть.
* хорошо бежать.
*
* @author Джо Стамп < [email protected] >
* @static
* @param смешанный $модуль
* @return логическое значение
*/
общедоступная статическая функция isValid($module)
{
return (is_object($module) &&
$module экземпляр FR_Module &&
$module экземпляр FR_Auth);
}
// }}}
// {{{ __destruct()
публичная функция __destruct()
{
родитель::__destruct();
}
// }}}
}
?>
Presenter.php — ядро уровня представления.
<?php
класс FR_Presenter
{
// {{{ фабрика($type,FR_Module $module)
/**
*фабрика
*
* @author Джо Стамп < [email protected] >
* @доступ к общедоступному
* @param string $type Тип представления (наш взгляд)
* @param mix $module Наш модуль, который будет отображать ведущий
* @return смешанный PEAR_Error при ошибке или допустимом презентаторе
* @static
*/
фабрика статических общедоступных функций ($type,FR_Module $module)
{
$file = FR_BASE_PATH.'/includes/Presenter/'.$type.'.php';
если (включить($файл)) {
$class = 'FR_Presenter_'.$type;
если (class_exists($class)) {
$presenter = новый $класс($модуль);
если ($ Presenter экземпляр FR_Presenter_common) {
вернуть $презентатор;
}
return PEAR::raiseError('Неверный класс представления: '.$type);
}
return PEAR::raiseError('Класс представления не найден: '.$type);
}
return PEAR::raiseError('Файл Presenter не найден: '.$type);
}
// }}}
}
?>
В следующей статье я представлю структуру контроллера (контроллер в MVC, index.php в этой статье). В третьей статье я представлю уровень представления (просмотр в MVC). В четвертой статье я буду использовать конкретный модуль в качестве примера для создания приложения (Модуль или Модель в MVC).