English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
1 ¿Qué es MVC
Patrón MVC (Model-View-(Controlador) es un patrón de arquitectura de software en ingeniería de software, que divide el sistema de software en tres partes básicas: modelo (Modelo), vista (View) y controlador (Controller).
El patrón MVC en PHP también se conoce como Web MVC, que se originó en el siglo7Surgió en la década de 0. El objetivo del MVC es implementar un diseño de programa dinámico, facilitando la modificación y expansión futuras del programa y permitiendo la reutilización de una parte del programa. Además, al simplificar la complejidad, la estructura del programa se vuelve más intuitiva. Al separar la parte básica del sistema de software, se otorgan a cada parte básica las funciones correspondientes.
Las funciones de las partes del MVC:
•modelo Model – gestiona la mayor parte de la lógica de negocio y toda la lógica de base de datos. El modelo proporciona una capa abstracta para conectar y operar con la base de datos.
•controlador Controller - Responsable de responder a las solicitudes del usuario, preparar datos y decidir cómo presentar los datos.
•vista View – responsable de renderizar datos, presentados al usuario a través de HTML.
Un flujo típico de MVC web:
1.Controller intercepta las solicitudes del usuario;
2.Controller llama al Model para completar las operaciones de lectura y escritura de estado;
3.Controller transmite datos a View;
4.View renderiza el resultado final y lo presenta al usuario.
2 ¿Por qué desarrollar un framework MVC oneself?
Hay muchos frameworks MVC excelentes disponibles en línea. Este tutorial no es para desarrollar una solución de framework MVC completa y definitiva, sino que se considera una buena oportunidad para aprender PHP desde el interior. En este proceso, aprenderás programación orientada a objetos y el patrón de diseño MVC, y también aprenderás algunas consideraciones importantes en el desarrollo.
Lo más importante es que puedes controlar completamente tu framework y integrar tus ideas en el framework que estás desarrollando. Aunque no necesariamente será el mejor, puedes desarrollar funciones y módulos a tu manera.
3 Comienza a desarrollar tu propio framework MVC
3.1 Preparación de directorios
Antes de comenzar a desarrollar, primero configuremos el proyecto. Supongamos que el proyecto que creamos se llama todo, y el framework MVC se puede nombrar FastPHP. Entonces, el primer paso es configurar la estructura de directorios.
Aunque en este tutorial no se utilizarán todos los directorios anteriores, es muy necesario configurar bien la estructura de directorios del programa al principio para facilitar la expansión futura del programa. A continuación, mencionaremos específicamente el papel de cada directorio:
•application – código de aplicación
•config – configuración del programa o configuración de la base de datos
•fastphp - Directorio del núcleo del marco
•public – archivos estáticos
•runtime - Directorio de datos temporales
•scripts – herramientas de línea de comandos
3.2 Normas de código
Después de configurar el directorio, debemos establecer algunas reglas de codificación:
1.Los nombres de las tablas de MySQL deben ser minúsculas, como: item, car
2.Los nombres de los módulos (Models) deben comenzar con mayúscula y agregar "Model" al final, como: ItemModel, CarModel
3.Los controladores (Controllers) deben comenzar con mayúscula y agregar "Controller" al nombre, como: ItemController, CarController
4.Estructura de despliegue de la vista (Views) es "Nombre del controlador/Nombre del comportamiento/view.php, car/buy.php
Algunas de las reglas anteriores son para facilitar las llamadas entre programas. Ahora comenzamos con el verdadero desarrollo de PHP MVC.
3.3 Redirige
Redirige todas las solicitudes de datos a un archivo index.php, en el directorio todo crea un archivo .htaccess, el contenido del archivo es:
<IfModule mod_rewrite.c> RewriteEngine On # Asegúrate de que la ruta de solicitud no sea un nombre de archivo o directorio RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d # Redirige todas las solicitudes a index.php?url=PATHNAME RewriteRule ^(.*)$ index.php?url=$1 [PT,L] </IfModule>
La razón principal para hacerlo es:
1.El programa tiene una única entrada;
2.Redirige todos los programas excepto los estáticos a index.php;
3.Se puede usar para generar URL beneficiosas para SEO, si se desea una configuración de URL mejorada, es posible que necesite rutas de URL más adelante, aquí no se introducirá.
3.4 Archivo de entrada
Después de realizar las operaciones anteriores, debería saber qué necesitamos hacer, ¡no es así! Añadir un archivo index.php en el directorio public, el contenido del archivo es:
<&63;php // El directorio de la aplicación es el directorio actual define('APP_PATH', __DIR__.'/'); // Activar el modo de depuración define('APP_DEBUG', true); // URL raíz del sitio define('APP_URL', 'http:)//localhost/fastphp'); // Cargar el marco require '.'/fastphp/FastPHP.php';
Nota, en el código PHP mencionado anteriormente, no se ha agregado el símbolo de finalización PHP”?>”,la razón principal de hacer esto es que para los archivos que contienen solo código PHP, el símbolo de finalización (“?>”)mejor no exista, PHP no necesita símbolos de finalización, no agregar símbolos de finalización puede evitar en gran medida que se añadan contenido adicional de inyección en el final, haciendo que el programa sea más seguro.
3.5 Configuración del archivo de configuración y solicitud principal
En el archivo index.php, hemos hecho una solicitud al archivo FastPHP.php ubicado en la carpeta fastphp, ¿qué contenido incluirá este archivo de inicio FastPHP.php realmente?
<&63;php // Inicializar constantes defined('FRAME_PATH') or define('FRAME_PATH', __DIR__.'/'); defined('APP_PATH') or define('APP_PATH', dirname($_SERVER['SCRIPT_FILENAME']).'/'); defined('APP_DEBUG') or define('APP_DEBUG', false); defined('CONFIG_PATH') or define('CONFIG_PATH', APP_PATH.'config/'); defined('RUNTIME_PATH') or define('RUNTIME_PATH', APP_PATH.'runtime/'); // Incluir el archivo de configuración require APP_PATH . 'config/config.php'; //Incluir la clase del marco nuclear require FRAME_PATH . 'Core.php'; // Instanciar la clase nuclear $fast = new Core; $fast->run();
Estos archivos se pueden incluir directamente en el archivo index.php, y los identificadores también se pueden definir directamente en index.php. Hacemos esto para facilitar la gestión y expansión en el futuro, por lo que reunimos todos los programas que deben ejecutarse al principio en un archivo separado para incluirlo.
Veamos primero el archivo config.php ubicado en el directorio config, que tiene como función establecer algunas opciones de configuración del programa y la conexión a la base de datos, y su contenido principal es:
<&63;php /** Configuración de variables **/ define('DB_NAME', 'todo'); define('DB_USER', 'root'); define('DB_PASSWORD', 'root'); define('DB_HOST', 'localhost');
Debería decirse que config.php no aborda mucho contenido, sino solo algunas configuraciones básicas de la base de datos. Ahora, echemos un vistazo a cómo escribir el archivo de entrada del marco compartido Core.php en fastphp.
<&63;php /** * Marco de trabajo FastPHP */ class Core { // Ejecutar el programa function run() { spl_autoload_register(array($this, 'loadClass')); $this->setReporting(); $this->removeMagicQuotes(); $this->unregisterGlobals(); $this->Route(); } // Manejo de rutas function Route() { $controllerName = 'Index'; $action = 'index'; if (!empty($_GET['url'])) { $url = $_GET['url']; $urlArray = explode('/', $url); // Obtener el nombre del controlador $controllerName = ucfirst($urlArray[0]); // Obtener el nombre de la acción array_shift($urlArray); $action = empty($urlArray[0]) ? 'index' : $urlArray[0]; //Obtener parámetros de la URL array_shift($urlArray); $queryString = empty($urlArray) ? array() : $urlArray; } // Manejo de datos vacíos $queryString = empty($queryString) ? array() : $queryString; // Instanciar el controlador $controller = $controllerName . 'Controller'; $dispatch = new $controller($controllerName, $action); // Si el controlador y la acción existen, se llama y se pasan los parámetros de la URL if ((int)method_exists($controller, $action)) { call_user_func_array(array($dispatch, $action), $queryString); } else { exit($controller . "Controlador no encontrado"); } } // Detectar entorno de desarrollo function setReporting() { if (APP_DEBUG === true) { error_reporting(E_ALL); ini_set('display_errors','On'); } else { error_reporting(E_ALL); ini_set('display_errors','Off'); ini_set('log_errors', 'On'); ini_set('error_log', RUNTIME_PATH. 'logs/error.log'); } } // Eliminar caracteres sensibles function stripSlashesDeep($value) { $value = is_array($value) ? array_map('stripSlashesDeep', $value) : stripslashes($value); return $value; } // Detectar y eliminar caracteres sensibles function removeMagicQuotes() { if ( get_magic_quotes_gpc()) { $_GET = stripSlashesDeep($_GET ); $_POST = stripSlashesDeep($_POST ); $_COOKIE = stripSlashesDeep($_COOKIE); $_SESSION = stripSlashesDeep($_SESSION); } } // Detectar y eliminar variables globales personalizadas (register globals) function unregisterGlobals() { if (ini_get('register_globals')) { $array = array('_SESSION', '_POST', '_GET', '_COOKIE', '_REQUEST', '_SERVER', '_ENV', '_FILES'); foreach ($array as $value) { foreach ($GLOBALS[$value] as $key => $var) { if ($var === $GLOBALS[$key]) { unset($GLOBALS[$key]); } } } } } // Cargar automáticamente las clases controlador y modelo función estática loadClass($class) { $frameworks = FRAME_PATH . $class . '.class.php'; $controllers = APP_PATH . 'application/controladores/' . $class . '.class.php'; $models = APP_PATH . 'application/modelos/' . $class . '.class.php'; if (file_exists($frameworks)) { // Cargar las clases nucleares del framework include $frameworks; } elseif (file_exists($controllers)) { // Cargar la clase controlador de aplicación include $controllers; } elseif (file_exists($models)) { //Cargar la clase modelo de aplicación include $models; } else { /* código de error */ } } }
A continuación, se explica en detalle el método principal de solicitud mainRequest callHook() primero, queremos ver cómo será nuestra URL:
yoursite.com/nombre de controlador/nombre de acción/cadena de consulta
La función callHook() tiene el propósito de obtener la URL desde la variable global GET[′url′] y dividirla en tres partes: obtener la URL desde GET[′url′] y dividirla en tres partes: controlador, acción y queryString。
Por ejemplo, el enlace URL es: todo.com/item/view/1/primero-item, entonces
•$controller es: item
•$action es: view
•La cadena de consulta Query String es: array(1, primero-item)
Después de la división, se instanciará un nuevo controlador: $controller.'Controller' (donde “.” es el guión), y se llamará su método $action。
3.6 Controlador/Clase base Controller
La siguiente operación es establecer las clases base necesarias para el programa en fastphp, incluyendo las clases base de controlador, modelo y vista。
La clase base del controlador se llama Controller.class.php, la función principal del controlador es la调度,los detalles específicos son los siguientes:
<&63;php /** * Clase base del controlador */ class Controller { protected $_controller; protected $_action; protected $_view; // Constructor, inicializar propiedades e instanciar el modelo correspondiente function __construct($controller, $action) { $this->_controller = $controller; $this->_action = $action; $this-_view = new View($controller, $action); } // assign variables function assign($name, $value) { $this-_view-assign($name, $value); } // Renderizar la vista function __destruct() { $this-_view-render(); } }
La clase Controller realiza la comunicación entre todos los controladores, modelos y vistas (clase View). Al ejecutar el destructor, podemos llamar a render() para mostrar el archivo de vista (view).
3.7 Clase base del modelo Model
Crear la clase base del modelo como Model.class.php, el código de la clase base del modelo Model.class.php es el siguiente:
<&63;php class Model extends Sql { protected $_model; protected $_table; function __construct() { // Conectar a la base de datos $this-connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME); // Obtener el nombre del modelo $this-_model = get_class($this); $this-_model = rtrim($this-_model, 'Model'); // El nombre de la tabla de la base de datos debe coincidir con el nombre de la clase $this-_table = strtolower($this-_model); } function __destruct() { } }
Dado que el modelo necesita manejar la base de datos, se ha creado una clase base de base de datos separada Sql.class.php, y la clase base del modelo hereda de Sql.class.php, el código es el siguiente:
<&63;php class Sql { protected $_dbHandle; protected $_result; // Conectar a la base de datos public function connect($host, $user, $pass, $dbname) { try { $dsn = sprintf("mysql:host=%s;dbname=%s;charset=utf8"$host, $dbname); $this-_dbHandle = new PDO($dsn, $user, $pass, array(PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC)); } catch (PDOException $e) { exit('Error: ' . $e->getMessage()); } } // Consultar todos public function selectAll() { $sql = sprintf("select * from `%s`", $this->_table); $sth = $this->_dbHandle->prepare($sql); $sth->execute(); return $sth->fetchAll(); } // Consultar según las condiciones (id) public function select($id) { $sql = sprintf("select * from `%s` where `id` = '%s'", $this->_table, $id); $sth = $this->_dbHandle->prepare($sql); $sth->execute(); return $sth->fetch(); } // Eliminar según las condiciones (id) public function delete($id) { $sql = sprintf("delete from `%s` where `id` = '%s'", $this->_table, $id); $sth = $this->_dbHandle->prepare($sql); $sth->execute(); return $sth->rowCount(); } // Consulta SQL personalizada, devuelve el número de filas afectadas public function query($sql) { $sth = $this->_dbHandle->prepare($sql); $sth->execute(); return $sth->rowCount(); } // Agregar nuevos datos public function add($data) { $sql = sprintf("insert into `%s` %s", $this->_table, $this->formatInsert($data)); return $this->query($sql); } // Modificar los datos public function update($id, $data) { $sql = sprintf("update `%s` set %s where `id` = '%s'", $this->_table, $this->formatUpdate($data), $id); return $this->query($sql); } // Convertir el array en una declaración SQL de formato de inserción private function formatInsert($data) { $fields = array(); $values = array(); foreach ($data as $key => $value) { $fields[] = sprintf("`%s`", $key); $values[] = sprintf("'%s'", $value); } $field = implode(',', $fields); $value = implode(',', $values); return sprintf("(%s) values (%s)", $field, $value); } // convert array to SQL update statement format private function formatUpdate($data) { $fields = array(); foreach ($data as $key => $value) { $fields[] = sprintf("`%s` = '%s'", $key, $value); } return implode(',', $fields); } }
Should be said, Sql.class.php is the core part of the framework. Why? Because through it, we have created a SQL abstraction layer that can greatly reduce the programming work of the database. Although the PDO interface is already very concise, the framework is more flexible after abstraction.
3.8 View class
The content of the View class View.class.php is as follows:
<&63;php /** * view base class */ class View { protected $variables = array(); protected $_controller; protected $_action; function __construct($controller, $action) { $this->_controller = $controller; $this->_action = $action; } /** assign variables **/ function assign($name, $value) { $this->variables[$name] = $value; } /** render display **/ function render() { extract($this->variables); $defaultHeader = APP_PATH . 'application/views/header.php'; $defaultFooter = APP_PATH . 'application/views/footer.php'; $controllerHeader = APP_PATH . 'application/views/' . $this->_controller . '/header.php'; $controllerFooter = APP_PATH . 'application/views/' . $this->_controller . '/footer.php'; // Archivo de encabezado de página if (file_exists($controllerHeader)) { include ($controllerHeader); } else { include ($defaultHeader); } // Archivo de contenido de página include (APP_PATH . 'application/views/' . $this->_controller . '/' . $this->_action . '.php'); // Archivo de pie de página if (file_exists($controllerFooter)) { include ($controllerFooter); } else { include ($defaultFooter); } } }
Así que hemos completado la escritura de nuestro núcleo del framework PHP MVC, ahora comenzamos a escribir la aplicación para probar las funciones del framework.
4 Aplicación
4.1 Despliegue de la base de datos
En SQL, crea una base de datos todo nueva y agrega la tabla item con las siguientes sentencias e inserta:2registros:
CREATE DATABASE `todo` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; USE `todo`; CREATE TABLE `item` ( `id` int(11) NOT NULL auto_increment, `item_name` varchar(255) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; INSERT INTO `item` VALUES(1, 'Hello World.'); INSERT INTO `item` VALUES(2, 'Lets go!');
4.2 Despliegue del modelo
Luego, también necesitamos crear un modelo ItemModel.php en el directorio models, con el siguiente contenido:
<&63;php class ItemModel extends Model { /* Implementación de la capa de lógica de negocio */ }
El contenido del modelo está vacío. Porque el modelo Item hereda de Model, tiene todas las funciones de Model.
4.3 Despliegue del controlador
En el directorio controllers, crea un controlador ItemController.php con el siguiente contenido:
<&63;php class ItemController extends Controller { // Método de página principal, prueba del marco DB consulta personalizada public function inicio() { $elementos = (new ItemModel)->seleccionarTodos(); $this->asignar('título', 'Todos los elementos'); $this->asignar('elementos', $elementos); } // Añadir registro, prueba del marco DB creación de registro (Crear) public function añadir() { $data['nombre_item'] = $_POST['valor']; $cuenta = (new ItemModel)->añadir($data); $this->asignar('título', 'Añadido exitosamente'); $this->asignar('cuenta', $cuenta); } // Ver registro, prueba del marco DB lectura de registro (Leer) public function ver($id = null) { $elemento = (new ItemModel)->seleccionar($id); $this->asignar('título', 'Viendo' . $elemento['nombre_item']); $this->asignar('elemento', $elemento); } // Actualizar registro, prueba del marco DB actualización de registro (Actualizar) public function actualizar() { $data = array('id' => $_POST['id'], 'nombre_item' => $_POST['valor']); $cuenta = (new ItemModel)->actualizar($data['id'], $data); $this->asignar('título', 'Actualización exitosa'); $this->asignar('cuenta', $cuenta); } // Eliminar registro, prueba del marco DB eliminación de registro (Eliminar) public function eliminar($id = null) { $cuenta = (new ItemModel)->eliminar($id); $this->asignar('título', 'Eliminación exitosa'); $this->asignar('cuenta', $cuenta); } }
4.4 Despliegue de vistas
En el directorio views, crear los archivos de plantilla de encabezado y pie de página header.php y footer.php, contenido como se muestra a continuación.
header.php,contenido:
<html> <cabecera> <meta http-equivalente="Contenido-Tipo" contenido="texto/html; charset=utf-8" /> <título><?php echo $title &63;></título> <estilo> .item { ancho:400px; } input { color:#222222; font-family:georgia,times; font-size:24px; font-weight:normal; line-height:1.2em; color:black; } a { color:blue; font-family:georgia,times; font-size:20px; font-weight:normal; line-height:1.2em; text-decoration:none; } a:hover { text-decoration:underline; } h1 { color:#000000; font-size:41px; letter-spacing:-2px; line-height:1em; font-family:helvetica,arial,sans-serif; border-bottom:1px dotted #cccccc; } h2 { color:#000000; font-size:34px; letter-spacing:-2px; line-height:1em; font-family:helvetica,arial,sans-serif; } </style> </head> <body> <h1><&63;php echo $title &63;></h1> footer.php,内容: </body> </html>
然后,在 views/item 创建以下几个视图文件。
index.php,浏览数据库内 item 表的所有记录,内容:
<form action="<&63;php echo APP_URL &63;>/item/add" method="post"> <input type="text" value="点击添加" onclick="this.value=''" name="value"> <input type="submit" value="添加"> </form> <br/><br/> <&63;php $number = 0&63;> <&63;php foreach ($items as $item): &63;> <a class="big" href="<63;php echo APP_URL &63;>/item/view/<&63;php echo $item['id'] &63;>" title="[#1#]"> <span class="item"> <&63;php echo ++$number &63;> <&63;php echo $item['item_name'] &63;> </span> </a> ---- <a class="big" href="<63;php echo APP_URL &63;>/item/delete/<&63;php echo $item['id']&63;>删除</a> <br/> <&63;php endforeach &63;>
add.php,添加记录,内容:
<a class="big" href="<63;php echo APP_URL &63;>/item/index">成功添加<&63;php echo $count &63;>条记录,点击返回</a>
view.php,查看单条记录,内容:
<form action="<&63;php echo APP_URL &63;>/item/update" method="post"> <input type="text" name="value" value="<&63;php echo $item['item_name'] &63;> <input type="hidden" name="id" value="<63;php echo $item['id'] &63;> <input type="submit" value="Modificar"> </form> <a class="big" href="<63;php echo APP_URL &63;>/item/;index>Regresar</a>
update.php, modificar registro, contenido:
<a class="big" href="<63;php echo APP_URL &63;>/item/;index>Modificado con éxito<63;php echo $count &63;>Artículo, haga clic para regresar</a>
delete.php, eliminar registro, contenido:
<a href="<63;php echo APP_URL &63;>/item/;index>Eliminado con éxito<63;php echo $count &63;>Artículo, haga clic para regresar</a>
4.5 Pruebas de aplicación
De esta manera, al acceder al programa todo en el navegador: http://localhost/todo/item/index/, puede ver los efectos.
El código se ha publicado completamente en github, se han agregado comentarios a las partes clave, la dirección del repositorio es:https://github.com/yeszao/fastphp, bienvenido a clonar y enviar.
Para diseñar un mejor MVC o usarlo de manera más normalizada, consultePrincipios de división de responsabilidades del arco MVC .
Esto es todo el contenido de este artículo, espero que sea útil para su aprendizaje y que todos nos apoyen en el tutorial de gritos.
Declaración: El contenido de este artículo se obtiene de la red, es propiedad del autor original, el contenido se contribuye y se carga por los usuarios de Internet, este sitio no posee los derechos de propiedad, no se ha editado artificialmente y no asume ninguna responsabilidad legal. Si encuentra contenido sospechoso de copyright, le invitamos a enviar un correo electrónico a: notice#oldtoolbag.com (al enviar un correo electrónico, reemplace # con @) para denunciar, y proporcione pruebas relacionadas. Una vez verificado, este sitio eliminará inmediatamente el contenido sospechoso de infracción.