[¿Qué es MVC? 】
MVC es un concepto que le permite combinar armoniosamente "tres partes (es decir, el nombre completo de MVC, Modelo, Vista y Controlador)" para formar una aplicación compleja. Un coche es un muy buen ejemplo de MVC en la vida real. Cuando miramos un automóvil, miramos dos partes de Vista (visualización): interior y exterior. Ambos son inseparables de un Responsable: el conductor. El sistema de frenos, el volante y otros sistemas de control representan el Modelo: toman los métodos de control del conductor (Controlador) y los aplican al interior y al exterior (Vista).
[MVC en la Web]
Los conceptos cubiertos por el marco MVC son bastante simples y extremadamente flexibles. El concepto básico es que tiene un único controlador (como index.php) que controla todas las aplicaciones dentro del marco que se basan en solicitudes de parámetros. Este controlador suele contener (como mínimo) un parámetro que define el modelo, un evento y un parámetro GET. De esta manera, el controlador puede reconocer todas las solicitudes y ejecutar los eventos apropiados. Por ejemplo, una solicitud como esta /index.php?module=foo&event=bar probablemente se use para cargar una clase llamada foo y luego ejecutar foo::bar()[que es la función bar()]. Las ventajas de esto son:
mantener una interfaz para todas las aplicaciones
mientras se mantienen innumerables códigos en una aplicación es muy problemático, porque cada fragmento de código tiene su propia ruta relativa, enlace de base de datos, verificación, etc. Hacerlo le ahorra problemas y le permite fusionar y reutilizar código
[¿Por qué crear su propio marco MVC? 】
Hasta ahora, no he visto muchos marcos MVC escritos en PHP. De hecho, sólo conozco uno: Solar, que está completamente escrito en PHP5. El otro es Cake, que intenta ser RoR (Ruby on Rails, un marco de red de código abierto para el lenguaje Ruby) de PHP. Yo mismo tengo cierta insatisfacción con ambos marcos: no aprovechan el código existente incluido en PEAR, Smarty, etc.; finalmente, el Cake actual todavía es relativamente complicado, Solar es un marco escrito principalmente por una sola persona; (No pretendo decir que su autor, Paul, no sea una buena persona ni un buen programador). Probablemente estas preguntas no te hagan negarlas y es probable que no te importen en absoluto. Pero por eso les pido que los miren tanto como sea posible.
[Forma antigua]
Si regresa a 2001 y observa el código que escribió, el autor puede encontrar un archivo llamado template.txt, que se ve así: www.phpv.net Indique la fuente para la reimpresión
<?php
require_once('config.php'); // Otros requisitos, información de la base de datos, etc.
$APP_DB = 'mydb';
$APP_REQUIRE_LOGIN = false // Establecer en verdadero si el script requiere iniciar sesión
$APP_TEMPLATE_FILE = 'foo.php'; // Plantilla inteligente
$APP_TITLE = 'Mi Solicitud';
si ($APP_REQUIRE_LOGIN == verdadero) {
if (!isset($_SESSION['ID de usuario'])) {
encabezado("Ubicación: /ruta/a/login.php");
salida();
}
}
$db = DB::connect('mysql://'.$DB_USER.':'.$DB_PASS.'@localhost/'.$APP_DB);
si (!PEAR::isError($db)) {
$db->setFetchMode(DB_FETCHMODE_ASSOC);
} demás {
morir($db->getMessage());
}
// Pon tu lógica aquí
// Genera la plantilla
include_once(APP_TEMPLATE_PATH.'/header.php');
include_once(APP_TEMPLATE_PATH.'/'.$APP_TEMPLATE_FILE);
include_once(APP_TEMPLATE_PATH.'/footer.php');
?>
Oh, Dios mío, solo mirar este código me da vergüenza. El concepto de este código es garantizar que cada aplicación pueda adaptarse a este método de procesamiento. Por ejemplo, puedo simplemente copiar template.txt en myapp.php, cambiar algunas variables y listo, se ejecutará. Aún así, este enfoque altamente organizado tiene algunos inconvenientes graves: ¿Qué pasaría
si mi jefe quisiera que el autor usara myapp.php para generar PDF en algunos casos, HTML en algunos casos y SOAP en algunos casos (solicitudes XML enviadas directamente)? ¿hacer?
¿Qué debo hacer si esta aplicación requiere autenticación IMAP o LDAP?
¿Cómo manejo los diferentes tipos de código (incluidas ediciones, actualizaciones y eliminaciones)?
¿Cómo manejo la autenticación multinivel (administrador o no administrador)?
¿Cómo habilito el almacenamiento en caché de resultados? www.phpv.net Indique la fuente para la reimpresión
[Nueva forma]
Coloque todo en este marco MVC y descubrirá que la vida es muy simple. Por favor compare el siguiente código:
<?php
clase myapp extiende FR_Auth_User
{
función pública __construct()
{
padre::__construct();
}
función pública __default()
{
// Haz algo aquí
}
función pública eliminar()
{ }
función pública __destruct()
{
padre::__destruct();
}
}
?>
Tenga en cuenta que este código obviamente no se utiliza para vincular a una base de datos, determinar si un usuario ha iniciado sesión o generar cualquier otra información. El controlador lo tiene todo.
Si quiero autenticarme en LDAP, puedo establecer FR_Auth_LDAP. El controlador puede reconocer ciertos métodos de salida (como $_GET['output']) y puede convertir a PDF o SOAP en cualquier momento. La eliminación del controlador de eventos solo es responsable de la eliminación y no se preocupa por nada más. Debido a que este módulo tiene una instancia de la clase FR_User, puede simplemente determinar si un usuario ha iniciado sesión, etc. Smarty, como motor de plantillas, controla naturalmente el caché, pero el controlador también puede controlar parte del caché.
Pasar de la forma antigua mencionada anteriormente a la forma MVC puede ser un concepto nuevo y desconocido para muchas personas, pero una vez que se cambia a ese concepto, será bastante difícil volver atrás.
[Construya la capa inferior]
Soy fanático de PEAR, especialmente de la clase PEAR_Error. PHP5 introduce una nueva clase incorporada "Excepción" que reemplaza a PEAR_Error. Pero PEAR_Error tiene algunas características más prácticas que Exception. Por lo tanto, los ejemplos del marco MVC en esta serie de artículos lo utilizarán para el manejo de errores. De todos modos, todavía tengo que usar Exception para obtener el error del constructor, ya que ellos mismos no pueden devolver el error.
El propósito de diseñar estas clases básicas es el siguiente:
Use PEAR para agregar rápidamente funciones a las clases básicas
para crear clases abstractas pequeñas y repetidamente prácticas para que los usuarios puedan desarrollar rápidamente aplicaciones en este marco.
Use
phpDocumentor para generar documentos para todas las clases básicas.
La jerarquía de clases se verá así:
- FR_Object proporcionará funcionalidad básica para que la utilicen todos los demás objetos (incluido el registro, setFrom() general, toArray())
- FR_Object_DB es una pequeña capa que proporciona enlaces de bases de datos a subclases y otras funciones
- FR_Module es la clase inferior de todas las aplicaciones (también llamadas módulos, modelos, etc.)
- FR_Auth es la clase inferior de todos los mecanismos de verificación
· FR_Auth_User es una clase de verificación utilizada para verificar todos los módulos que necesitan verificar si el usuario ha iniciado sesión
· FR_Auth_No es todas las "clases de validación falsas" para módulos que no requieren validación
- FR_Presenter es la clase subyacente para todas las aplicaciones que manejan la carga y visualización
- FR_Presenter_Smarty es la capa de presentación que incluye la capacidad de cargar diferentes unidades. Smarty es una clase de plantilla muy buena. Tiene un mecanismo de almacenamiento en caché incorporado y un grupo de desarrollo activo (Nota del traductor: esto es obviamente un anuncio~)
· FR_Presenter_debug es la capa de visualización de la parte de depuración. Confiando en él, los desarrolladores pueden depurar aplicaciones y depurarlas
. FR_Presenter_rest es una capa de presentación REST que permite a los desarrolladores generar aplicaciones en XML.
Desde la estructura de clases básica anterior, debería poder ver las diferentes partes de este marco MVC. FR_Module proporciona todo lo que necesita el módulo, mientras que FR_Presenter proporciona diferentes métodos de visualización. En el próximo artículo de esta serie, crearé un controlador que une todas las clases base anteriores.
[Estándares de codificación]
Antes de escribir código formalmente, debe sentarse y discutir (o pensar en) los estándares de codificación con sus socios (o usted mismo). La idea general de la programación MVC gira en torno a dos puntos: la reutilización del código (reduciendo la coincidencia) y la estandarización del código. Recomiendo considerar al menos los siguientes puntos:
Lo primero a considerar son los estándares de abreviatura y denominación variable. No te metas en una gran pelea con tus socios por esto, pero una vez que se establecen los estándares, se deben seguir de principio a fin, especialmente al escribir código de bajo nivel (clases base).
Personalice un prefijo estándar para usarlo en todas las funciones, clases y variables globales. Desafortunadamente, PHP no admite "espacio de nombres (espacio de nombres)". Por lo tanto, para evitar confusiones y conflictos con los nombres de las variables, es aconsejable utilizar un prefijo. Usaré "FR_" como prefijo a lo largo de este artículo.
[Escribir la capa inferior]
La planificación a nivel de archivo es muy importante. La planificación jerárquica básica es simple y algo definida:
/
configuración.php
index.php
incluye/
autenticación.php
Autenticación/
No.php
Usuario.php
módulo.php
Objeto.php
Objeto/
DB.php
Presentador.php
Presentador/
común.php
depurar.php
sabelotodo.php
Sabelotodo/
módulos/
ejemplo/
configuración.php
ejemplo.php
tpl/
ejemplo.tpl
tpl/
por defecto/
cache/
configuración/
plantillas/
templates_c/
¡Podrías pensar que dicha jerarquía de archivos debe representar una gran cantidad de código! Es cierto, pero puedes hacerlo. Al final de la serie, descubrirá que su programación será más fácil y su velocidad de desarrollo mejorará enormemente.
En la jerarquía de archivos, todas las clases básicas están en la carpeta de inclusión. Cada módulo funcional utiliza un archivo de configuración, al menos un archivo de módulo y un archivo de plantilla. Todos los módulos están contenidos en la carpeta de módulos. Me he acostumbrado a colocar archivos de plantilla en una carpeta externa separada, la carpeta tpl.
config.php: el archivo de configuración central, que contiene todas las variables de configuración global.
index.php: controlador, se describirá en detalle en el próximo artículo.
object.php: la clase subyacente para todas las clases básicas, que proporciona la mayor parte de la funcionalidad que necesita la clase. FR_Object_DB hereda esta clase y proporciona enlaces a bases de datos.
El concepto básico de una estructura es que todas las subclases hereden de una clase central para que todas compartan algunas características comunes. Puede poner la función de vincular la base de datos en FR_Object, pero no todas las clases necesitan esta función, por lo que FR_Object_DB tiene una razón de existencia, y el autor lo discutirá más adelante.
<?php
require_once('Log.php');
/**
*FR_Objeto
*
* La clase de objeto base para la mayoría de las clases que usamos en nuestro marco.
* Proporciona funciones básicas de registro y configuración/obtención.
*
* @autor Joe Stump < [email protected] >
* @paqueteFramework
*/
clase abstracta FR_Object
{
/**
* $registro
*
* @var Mixed $log Instancia de PEAR Log
*/
protegido $registro;
/**
*$yo
*
* @var instancia $me mixta de ReflectionClass
*/
protegido $yo;
/**
* __construir
*
* @autor Joe Stump < [email protected] >
* @acceso público
*/
función pública __construct()
{
$this->log = Log::factory('archivo',FR_LOG_FILE);
$this->yo = new ReflectionClass($this);
}
/**
* establecer desde
*
* @autor Joe Stump < [email protected] >
* @acceso público
* @param mixto $data Matriz de variables para asignar a la instancia
* @retorno nulo
*/
función pública setFrom($datos)
{
si (is_array($datos) && recuento($datos)) {
$válido = get_class_vars(get_class($this));
foreach ($válido como $var => $val) {
si (isset($datos[$var])) {
$this->$var = $datos[$var];
}
}
}
}
/**
* a matriz
*
* @autor Joe Stump < [email protected] >
* @acceso público
* @return Matriz mixta de variables miembro codificadas por nombre de variable
*/
función pública toArray()
{
$valores predeterminados = $this->yo->getDefaultProperties();
$retorno = matriz();
foreach ($valor predeterminado como $var => $val) {
si ($this->$var instancia de FR_Object) {
$return[$var] = $this->$var->toArray();
} demás {
$retorno[$var] = $this->$var;
}
}
devolver $retorno;
}
/**
* __destruir
*
* @autor Joe Stump < [email protected] >
* @acceso público
* @retorno nulo
*/
función pública __destruct()
{
si ($this->log instancia de registro) {
$this->log->close();
}
}
}
?>
auth.php: esta es la clase subyacente para todas las funciones de autenticación. Es una extensión de FR_Module y su función principal es definir cómo funciona una clase de verificación básica.
Al igual que FR_Module, algunas clases no necesitan estar conectadas a la base de datos. Del mismo modo, FR_Auth_No se puede crear y aplicar a clases que no requieren funciones de autenticación.
<?php
la clase abstracta FR_Auth extiende FR_Module
{
// {{{ __construcción()
función__construcción()
{
padre::__construct();
}
// }}}
// {{{ autenticar()
función abstracta autenticar();
// }}}
// {{{ __destruct()
función __destruct()
{
padre::__destruct();
}
// }}}
}
?>
module.php - el corazón de todos los módulos
<?php
clase abstracta FR_Module extiende FR_Object_Web
{
// {{{ propiedades
/**
* $presentador
*
* Usado en FR_Presenter::factory() para determinar qué presentación (vista)
* la clase debe usarse para el módulo.
*
* @autor Joe Stump < [email protected] >
* @var cadena $presentador
* @ver FR_Presenter, FR_Presenter_common, FR_Presenter_smarty
*/
public $presentador = 'inteligente';
/**
* $datos
*
* Datos establecidos por el módulo que eventualmente se pasarán a la vista.
*
* @autor Joe Stump < [email protected] >
* @var mixto $data Datos del módulo
* @ver FR_Module::set(), FR_Module::getData()
*/
protegido $datos = matriz()
/**
* $nombre
*
* @autor Joe Stump < [email protected] >
* @var string $name Nombre de la clase del módulo
*/
público $nombre
/**
* $tplArchivo
*
* @autor Joe Stump < [email protected] >
* @var string $tplFile Nombre del archivo de plantilla
* @ver FR_Presenter_smarty
*/
público $tplArchivo
/**
* $nombredelmódulo
*
* @autor Joe Stump < [email protected] >
* @var string $moduleName Nombre del módulo solicitado
* @ver FR_Presenter_smarty
*/
public $nombredelmódulo = null;
/**
* $páginaArchivoPlantilla
*
* @autor Joe Stump < [email protected] >
* @var string $pageTemplateFile Nombre de la plantilla de página exterior
*/
público $pageTemplateFile = null;
// }}}
// {{{ __construcción()
/**
* __construir
*
* @autor Joe Stump < [email protected] >
*/
función pública __construct()
{
padre::__construct();
$this->nombre = $this->yo->getName();
$this->tplFile = $this->nombre.'.tpl';
}
// }}}
// {{{ __por defecto()
/**
* __por defecto
*
* Esta función la ejecuta el controlador si no se especifica un evento
* en la solicitud del usuario.
*
* @autor Joe Stump < [email protected] >
*/
función pública abstracta __default();
// }}}
// {{{ conjunto($var,$val)
/**
* colocar
*
* Establezca datos para su módulo. Esto eventualmente se pasará al usuario.
* clase de presentador a través de FR_Module::getData().
*
* @autor Joe Stump < [email protected] >
* @param string $var Nombre de la variable
* @param mixto $val Valor de la variable
* @retorno nulo
* @ver FR_Module::getData()
*/
conjunto de funciones protegidas($var,$val) {
$this->datos[$var] = $val;
}
// }}}
// {{{ obtenerDatos()
/**
*obtenerDatos
*
* Devuelve los datos del módulo.
*
* @autor Joe Stump < [email protected] >
* @retorno mixto
* @ver FR_Presenter_common
*/
función pública getData()
{
devolver $this->datos;
}
// }}}
// {{{ es válido($módulo)
/**
*es válido
*
* Determina si $module es un módulo de marco válido. Esto es utilizado por.
* el controlador para determinar si el módulo encaja en nuestro marco
* molde si se extiende tanto desde FR_Module como desde FR_Auth, entonces debería serlo.
* bueno para correr.
*
* @autor Joe Stump < [email protected] >
* @estático
* @param módulo $ mixto
* @return bool
*/
función estática pública es válida ($módulo)
{
retorno (is_object($módulo) &&
$ módulo instancia de FR_Module &&
$módulo instancia de FR_Auth);
}
// }}}
// {{{ __destruct()
función pública __destruct()
{
padre::__destruct();
}
// }}}
}
?>
presenter.php: el núcleo de la capa de presentación.
<?php
clase FR_Presenter
{
// {{{ fábrica($tipo,FR_Module $módulo)
/**
*fábrica
*
* @autor Joe Stump < [email protected] >
* @acceso público
* @param string $type Tipo de presentación (nuestra opinión)
* @param mixto $module Nuestro módulo, que mostrará el presentador
* @return PEAR_Error mixto en caso de falla o un presentador válido
* @estático
*/
fábrica de funciones públicas estáticas ($tipo,FR_Module $módulo)
{
$archivo = FR_BASE_PATH.'/includes/Presenter/'.$tipo.'.php';
si (incluir ($archivo)) {
$clase = 'FR_Presenter_'.$tipo;
si (class_exists($clase)) {
$presentador = nueva $clase($módulo);
si ($presentador instancia de FR_Presenter_common) {
devolver $presentador;
}
return PEAR::raiseError('Clase de presentación no válida: '.$tipo);
}
return PEAR::raiseError('Clase de presentación no encontrada: '.$tipo);
}
return PEAR::raiseError('Archivo del presentador no encontrado: '.$tipo);
}
// }}}
}
?>
En el próximo artículo, presentaré la estructura del controlador (Controlador en MVC, index.php en este artículo). En el tercer artículo, presentaré la capa de presentación (Ver en MVC). En el cuarto artículo, usaré un módulo específico como ejemplo para crear una aplicación (Módulo o Modelo en MVC).