English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
1 Cos'è MVC
Il modello MVC (Model-View-Controller) è un modello di architettura software nell'ingegneria del software, che suddivide il sistema software in tre parti fondamentali: modello (Model), vista (View) e controller (Controller).
Il modello MVC in PHP, noto anche come Web MVC, è evoluto dalla fine del XX secolo. Lo scopo del modello MVC è di realizzare una progettazione dinamica del programma, facilitando la modifica e l'estensione successiva del programma e rendendo possibile il riutilizzo di una parte del programma. Inoltre, semplificando la complessità, questo modello rende la struttura del programma più intuitiva. Il sistema software, separando i suoi componenti fondamentali, ha anche attribuito alle parti fondamentali le funzioni appropriate.
Le funzioni di ciascuna parte del MVC:
• Modello Model – Gestisce la maggior parte della logica aziendale e tutta la logica del database. Il modello fornisce uno strato astratto per connettersi e operare il database.
• Controller – Responsabile di rispondere alle richieste dell'utente, preparare i dati e determinare come presentare i dati.
• Visualizzazione View – Responsabile della presentazione dei dati, presentati all'utente tramite HTML.
Un flusso tipico di Web MVC:
1. Il Controller intercetta le richieste dell'utente;
2. Il Controller chiama il Model per completare le operazioni di lettura e scrittura di stato;
3. Il Controller trasmette i dati al View;
4. Visualizza i risultati finali e li presenta all'utente.
2. Perché sviluppare una propria MVC framework
Sul web ci sono molte excellenti framework MVC disponibili, questa guida non è volta a sviluppare una soluzione MVC completa e definitiva, ma è vista come una buona opportunità per imparare PHP internamente, durante questo processo, imparerai programmazione orientata agli oggetti e design pattern MVC, e imparerai alcune cose da considerare durante lo sviluppo.
Più importante ancora, puoi controllare completamente il tuo framework e integrare le tue idee nel framework che stai sviluppando. Anche se non è necessariamente il migliore, puoi sviluppare funzioni e moduli nel tuo modo.
3. Inizia a sviluppare la tua own MVC framework
3.1 Preparazione della directory
Prima di iniziare a sviluppare, diamo prima avvio al nostro progetto, supponiamo che il progetto che stiamo creando sia todo, il framework MVC può essere chiamato FastPHP, quindi il primo passo è configurare la struttura della directory.
Nonostante non utilizzeremo tutte le directory in questa guida, è molto importante configurare la directory del programma all'inizio per garantire l'estensibilità del programma in futuro. Di seguito, esamineremo l'uso di ciascuna directory:
•application – Codice dell'applicazione
•config – Configurazione del programma o configurazione del database
•fastphp – Directory del core della framework
•public – File statici
•runtime – Directory dei dati temporanei
•scripts – Strumenti della riga di comando
3.2 Norme del codice
Dopo aver configurato la directory, dobbiamo stabilire alcune norme per il codice:
1. Il nome delle tabelle MySQL deve essere in minuscolo, ad esempio: item, car
2. Il nome del modulo (Models) deve iniziare con una lettera maiuscola e aggiungere "Model" alla fine, ad esempio: ItemModel, CarModel
3. I controller (Controllers) devono avere la lettera maiuscola iniziale e aggiungere “Controller” nel nome, ad esempio: ItemController, CarController
4. La struttura di distribuzione delle viste (Views) è di tipo “nome_del_controllore/nome_dellazione”, ad esempio: item/view.php, car/buy.php
Alcune delle regole sopra sono per facilitare le chiamate reciproche nel programma. Ora iniziamo la programmazione PHP MVC vera e propria.
3.3 Reindirizzamento
Reindirizza tutte le richieste di dati al file index.php, crea un file .htaccess nella directory todo, il contenuto del file è:
<IfModule mod_rewrite.c> RewriteEngine On # Assicurati che il percorso della richiesta non sia un nome di file o una directory RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d # Reindirizza tutte le richieste a index.php?url=PATHNAME RewriteRule ^(.*)$ index.php?url=$1 [PT,L] </IfModule>
La ragione principale per farlo è:
1. Il programma ha un singolo punto di ingresso;
2. Oltre ai programmi statici, tutti gli altri programmi vengono reindirizzati a index.php;
3. Può essere utilizzato per generare URL favorevoli all'SEO, per una configurazione migliore dell'URL, potrebbe essere necessario il routing dell'URL in futuro, questa parte non sarà spiegata ora.
3.4 File di ingresso
Dopo aver completato le operazioni sopra, dovrebbe essere chiaro cosa dobbiamo fare, giusto! Aggiungi il file index.php nella directory public, il contenuto del file è:
<?php // La directory dell'applicazione è la directory corrente define('APP_PATH', __DIR__.'/'); // Abilita la modalità di debug define('APP_DEBUG', true); // URL radice del sito define('APP_URL', 'http://localhost/fastphp'); // Carica la struttura require './fastphp/FastPHP.php';
Attenzione, il codice PHP sopra non aggiunge il simbolo di fine PHP”?>”, la ragione principale è che per i file che contengono solo codice PHP, il segno di fine (“?>”) è meglio non esistere, PHP non richiede un simbolo di fine, e non aggiungere il simbolo di fine può prevenire in gran parte l'inserimento di contenuti di intrusione extra alla fine, rendendo il programma più sicuro.
3.5 File di configurazione e richiesta principale
Nel file index.php, abbiamo inviato una richiesta al file FastPHP.php nella cartella FastPHP, quindi cosa contiene esattamente il file di avvio FastPHP.php?
<?php // Inizializzare le costanti 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/'); // Include il file di configurazione require APP_PATH . 'config/config.php'; // Include la classe del framework principale require FRAME_PATH . 'Core.php'; // Eseguire l'istanziazione della classe principale $fast = new Core; $fast->run();
Questi file possono essere inclusi direttamente nel file index.php, e le costanti possono essere definite direttamente in index.php. Facciamo così per rendere più facile la gestione e l'espansione in futuro, quindi mettiamo insieme i programmi che devono essere caricati e eseguiti all'inizio in un file separato per il riferimento.
Prima di tutto, vediamo il file config.php nel percorso config del file, il principale scopo di questo file è impostare alcune opzioni di configurazione del programma e la connessione del database, il contenuto principale è:
<?php /** Configurazione delle variabili **/ define('DB_NAME', 'todo'); define('DB_USER', 'root'); define('DB_PASSWORD', 'root'); define('DB_HOST', 'localhost');
Dovrebbe essere detto che config.php coinvolge relativamente poco contenuto, sono solo alcune impostazioni di base del database, e ora vediamo come scrivere il file di ingresso comune del framework under fastphp, Core.php.
<?php /** * Frame di lavoro FastPHP */ class Core { // Esecuzione del programma function run() { spl_autoload_register(array($this, 'loadClass')); $this->setReporting(); $this->removeMagicQuotes(); $this->unregisterGlobals(); $this->Route(); } // Gestione delle rotte function Route() { $controllerName = 'Index'; $action = 'index'; if (!empty($_GET['url'])) { $url = $_GET['url']; $urlArray = explode('/', $url); // Prelievo del nome del controller $controllerName = ucfirst($urlArray[0]); // Prelievo del nome dell'azione array_shift($urlArray); $action = empty($urlArray[0]) ? 'index' : $urlArray[0]; // Prelievo dei parametri dell'URL array_shift($urlArray); $queryString = empty($urlArray) ? array() : $urlArray; } // Gestione dei dati vuoti $queryString = empty($queryString) ? array() : $queryString; // Istanziazione del controller $controller = $controllerName . 'Controller'; $dispatch = new $controller($controllerName, $action); // Se il controller e l'azione esistono, questa viene chiamata e i parametri dell'URL vengono trasmessi if ((int)method_exists($controller, $action)) { call_user_func_array(array($dispatch, $action), $queryString); } else { exit($controller . "Controller non esistente"); } } // Verifica l'ambiente di sviluppo 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'); } } // Remove sensitive characters function stripSlashesDeep($value) { $value = is_array($value) ? array_map('stripSlashesDeep', $value) : stripslashes($value); return $value; } // Detect and remove sensitive characters function removeMagicQuotes() { if ( get_magic_quotes_gpc()) { $_GET = stripSlashesDeep($_GET ); $_POST = stripSlashesDeep($_POST ); $_COOKIE = stripSlashesDeep($_COOKIE); $_SESSION = stripSlashesDeep($_SESSION); } } // Detect and remove custom global variables (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]); } } } } } // Automatic loading of controller and model classes static function loadClass($class) { $frameworks = FRAME_PATH . $class . '.class.php'; $controllers = APP_PATH . 'application/controllers/' . $class . '.class.php'; $models = APP_PATH . 'application/models/' . $class . '.class.php'; if (file_exists($frameworks)) { // Carica le classi core del framework include $frameworks; } elseif (file_exists($controllers)) { // Carica la classe controller dell'applicazione include $controllers; } elseif (file_exists($models)) { // Carica la classe modello dell'applicazione include $models; } else { /* Codice di errore */ } } }
Ecco un'analisi dettagliata del metodo di richiesta principale callHook(), prima di tutto, vorremmo vedere come il nostro URL sarà:
yoursite.com/controllerName/actionName/queryString
La funzione callHook() ha il ruolo di ottenere l'URL dal variabile globale G ET[ ′ url ′ ]e dividerlo in tre parti: ottenere l'URL dal variabile globale G ET[′url′]e dividerlo in tre parti: controller, action e queryString.
Ad esempio, se l'URL è: todo.com/item/view/1/first-item, allora
• $controller è: item
• $action è: view
• La stringa di ricerca Query String è: array(1, first-item)
Dopo la divisione, viene istanziato un nuovo controller: $controller.'Controller' (dove “.” è il trattino), e viene chiamato il metodo $action.
3.6 Classe base / Controller
Le operazioni successive consistono nel creare le classi base necessarie per il programma in fastphp, inclusi le classi base dei controller, dei modelli e delle viste.
Nuova classe base del controller creata come Controller.class.php, la funzione principale del controller è la gestione di base, i dettagli specifici sono come segue:
<?php /** * Classe base del controller */ class Controller { protected $_controller; protected $_action; protected $_view; // Costruttore, inizializzazione delle proprietà e istanziazione del modello corrispondente function __construct($controller, $action) { $this->_controller = $controller; $this->_action = $action; $this->_view = new View($controller, $action); } // Assegnazione di variabili function assign($name, $value) { $this->_view->assign($name, $value); } // Renderizzazione della vista function __destruct() { $this->_view->render(); } }
La classe Controller implementa la comunicazione tra tutti i controller, modelli e viste (classe View). Durante l'esecuzione del costruttore distruttore, possiamo chiamare render() per visualizzare il file di vista (view).
3.7 Modello Model base
Ecco il modello base Model.class.php, il modello base Model.class.php è il seguente:
<?php class Model extends Sql { protected $_model; protected $_table; function __construct() { // Connettione al database $this->connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME); // Ottenere il nome del modello $this->_model = get_class($this); $this->_model = rtrim($this->_model, 'Model'); // Il nome della tabella del database è uguale al nome della classe $this->_table = strtolower($this->_model); } function __destruct() { } }
Considerando che il modello deve gestire il database, è stato creato un database base, Sql.class.php, il modello base eredita Sql.class.php, il codice è il seguente:
<?php class Sql { protected $_dbHandle; protected $_result; // Connettione al database 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)); } exit('Error: ' . $e->getMessage()); } } // Query all public function selectAll() { $sql = sprintf("select * from `%s`", $this->_table); $sth = $this->_dbHandle->prepare($sql); $sth->execute(); return $sth->fetchAll(); } // Query based on condition (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(); } // Delete based on condition (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(); } // Custom SQL query, return the number of affected rows public function query($sql) { $sth = $this->_dbHandle->prepare($sql); $sth->execute(); return $sth->rowCount(); } // Add new data public function add($data) { $sql = sprintf("insert into `%s` %s", $this->_table, $this->formatInsert($data)); return $this->query($sql); } // Modify data public function update($id, $data) { $sql = sprintf("update `%s` set %s where `id` = '%s'", $this->_table, $this->formatUpdate($data), $id); return $this->query($sql); } // Convert array to insert format SQL statement 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); } // Convertire l'array in una stringa SQL di aggiornamento private function formatUpdate($data) { $fields = array(); foreach ($data as $key => $value) { $fields[] = sprintf("`%s` = '%s'", $key, $value); } return implode(',', $fields); } }
Dovrebbe essere detto che Sql.class.php è una parte fondamentale del framework. Perché? Perché attraverso di esso, abbiamo creato uno strato di astrazione SQL, che può ridurre notevolmente il lavoro di programmazione del database. Anche se l'interfaccia PDO è già abbastanza sintetica, l'astrazione rende il framework ancora più flessibile.
3.8 视图View类
视图类 View.class.php 内容如下:
<?php /** * 视图基类 */ class View { protected $variables = array(); protected $_controller; protected $_action; function __construct($controller, $action) { $this->_controller = $controller; $this->_action = $action; } /** 分配变量 **/ function assign($name, $value) { $this->variables[$name] = $value; } /** 渲染显示 **/ 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'; // 文件页头 if (file_exists($controllerHeader)) { include ($controllerHeader); } else { include ($defaultHeader); } // 文件页内容 include (APP_PATH . 'application/views/' . $this->_controller . '/' . $this->_action . '.php'); // 文件页脚 if (file_exists($controllerFooter)) { include ($controllerFooter); } else { include ($defaultFooter); } } }
这样我们的核心的PHP MVC框架就编写完成了,下面我们开始编写应用来测试框架功能。
4 应用
4.1 部署数据库
在 SQL 中新建一个 todo 数据库,使用下面的语句增加 item 数据表并插入2条记录:
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 Distribuzione del modello
Poi, dobbiamo creare un modello ItemModel.php nella directory models, contenente il seguente codice:
<?php class ItemModel extends Model { /* Implementazione della logica di business */ }
Il contenuto del modello è vuoto. Poiché il modello Item eredita da Model, possiede tutte le funzionalità di Model.
4.3 Distribuzione del controller
Crea un controller ItemController.php nella directory controllers, contenente il seguente codice:
<?php class ItemController extends Controller { // Metodo首页,test framework custom DB query public function index() { $items = (new ItemModel)->selectAll(); $this->assign('title', 'Tutti gli elementi'); $this->assign('items', $items); } // Aggiungi il record, test framework DB record create (Create) public function add() { $data['item_name'] = $_POST['value']; $count = (new ItemModel)->add($data); $this->assign('title', 'Aggiunta con successo'); $this->assign('count', $count); } // Visualizza il record, test framework DB record read (Read) public function view($id = null) { $item = (new ItemModel)->select($id); $this->assign('title', 'Visualizzazione in corso' . $item['item_name']); $this->assign('item', $item); } // Aggiorna il record, test framework DB record update (Update) public function update() { $data = array('id' => $_POST['id'], 'item_name' => $_POST['value']); $count = (new ItemModel)->update($data['id'], $data); $this->assign('title', 'Modifica avvenuta con successo'); $this->assign('count', $count); } // Eliminazione dei record, test della funzionalità di eliminazione del framework DB (Delete) public function delete($id = null) { $count = (new ItemModel)->delete($id); $this->assign('title', 'Eliminazione avvenuta con successo'); $this->assign('count', $count); } }
4.4 Implementazione delle viste
Creare due modelli di intestazione e piè di pagina header.php e footer.php nella directory views, con il seguente contenuto.
header.php, contenuto:
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title><?php echo $title ?></title> <style> .item { width: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><?php echo $title ?></h1> footer.php, contenuto: </body> </html>
Poi, crea i seguenti file di vista nella directory views/item.
index.php, esplora tutti i record della tabella item nel database, contenuto:
<form action="<?php echo APP_URL ?>/item/add" method="post"> <input type="text" value="Clicca per aggiungere" onclick="this.value=''" name="value"> <input type="submit" value="Aggiungi"> </form> <br/><br/> <?php $number = 0?> <?php foreach ($items as $item): ?> <a class="big" href="<?php echo APP_URL ?>/item/view/<?php echo $item['id'] ?>" title="[#1#]"> <span class="item"> <?php echo ++$number ?> <?php echo $item['item_name'] ?> </span> </a> ---- <a class="big" href="<?php echo APP_URL ?>/item/delete/<?php echo $item['id']?>">Elimina</a> <br/> <?php endforeach ?>
add.php, aggiungi registrazione, contenuto:
<a class="big" href="<?php echo APP_URL ?>/item/index">Aggiunto con successo <?php echo $count ?> record, clicca per tornare</a>
view.php, visualizza una registrazione singola, contenuto:
<form action="<?php echo APP_URL ?>/item/update" method="post"> <input type="text" name="value" value="<?php echo $item['item_name'] ?>"> <input type="hidden" name="id" value="<?php echo $item['id'] ?>"> <input type="submit" value="Modifica"> </form> <a class="big" href="<?php echo APP_URL ?>/item/index">Torna indietro</a>
update.php, modifica i record, contenuto:
<a class="big" href="<?php echo APP_URL ?>/item/index">Modificati <?php echo $count ?> elementi, clicca per tornare</a>
delete.php, elimina i record, contenuto:
<a href="<?php echo APP_URL ?>/item/index">Eliminati <?php echo $count ?> elementi, clicca per tornare</a>
4.5 Test di applicazione
In questo modo, visitando il programma todo nel browser: http://localhost/todo/item/index/, puoi vedere l'effetto.
Tutto il codice è stato pubblicato su github, le parti chiave sono state commentate, l'indirizzo del repository:https://github.com/yeszao/fastphp, benvenuti a clonare e inviare contributi.
Per progettare un MVC migliore o utilizzare in modo più standardizzato, vederePrincipi di assegnazione delle responsabilità dell'architettura MVC .
Questo è tutto il contenuto dell'articolo, speriamo che sia utile per la tua apprendimento, e ti preghiamo di sostenere e fare eco della guida.
Dichiarazione: il contenuto di questo articolo è stato tratto da Internet, il copyright è dell'autore originale, il contenuto è stato contribuito autonomamente dagli utenti di Internet e caricato autonomamente, il sito web non detiene i diritti di proprietà, non è stato editato manualmente e non assume responsabilità legali correlate. Se trovi contenuti sospetti di violazione del copyright, ti preghiamo di inviare una e-mail a notice#oldtoolbag.com (sostituisci # con @) per segnalare il problema e fornire prove pertinenti. Una volta verificata, il sito eliminerà immediatamente il contenuto sospetto di violazione del copyright.