Use php to build your own mvc framework
1. What is MVC
MVC pattern (Model-View-Controller) is a software architecture pattern in software engineering, which divides the software system into three basic parts: Model, View and Controller (Controller).
The purpose of the MVC pattern is to implement a dynamic program design, simplify subsequent modifications and expansions of the program, and make it possible to reuse certain parts of the program. In addition, this mode makes the program structure more intuitive by simplifying the complexity. The software system separates its basic parts and also gives each basic part its due functions. Professionals can be grouped by their own expertise:
(Controller) - Responsible for forwarding requests and processing them.
(View) – Interface designers design graphical interfaces.
(Model) – Programmers write the functions that the program should have (implementing algorithms, etc.), and database experts perform data management and database design (can realize specific functions).
Model "Data model" (Model) is used to encapsulate data related to the business logic of the application and how to process the data. A "model" has direct access to data, such as a database. The "model" does not depend on the "view" and "controller", that is, the model does not care how it will be displayed or how it will be manipulated. However, changes in data in the model are generally announced through a refresh mechanism. In order to implement this mechanism, those views used to monitor this model must be registered on this model in advance, so that the views can understand the changes that occur in the data model.
View The view layer enables purposeful display of data (in theory, this is not necessary). There is generally no procedural logic in views. In order to implement the refresh function on the view, the view needs to access the data model (Model) it monitors, so it should be registered in advance with the data it monitors.
Controller (Controller) The controller plays an organizational role between different levels and is used to control the flow of the application. It handles events and responds. "Events" include user behavior and changes in the data model.
2. Why should you develop your own MVC framework?
There are a large number of excellent MVC frameworks available on the Internet. This tutorial is not intended to develop a comprehensive and ultimate MVC framework solution, but to regard it as a very A great opportunity to learn PHP from the inside. In the process, you will learn object-oriented programming and design patterns, and learn some considerations in opening.
What’s more, you have full control over your framework and incorporate your ideas into the framework you develop. Although it is not necessarily done well, you can develop functions and modules in your own way.
3. Start developing your own MVC framework
Before starting development, let us first establish the project. Assuming that the project we create is todo, the next step is to set up the directory structure first.
Although all the above directories will not be used in this tutorial, it is very necessary to set the program directory at the beginning for the scalability of the program in the future. Let’s talk about the role of each directory in detail:
application – to store program code
config – to store program configuration or database configuration
db – to store database backup content
library – to store framework code
public – to store Static files
scripts - stores command line tools
tmp - stores temporary data
After the directory is set, we will follow some code specifications:
MySQL table names must be lowercase and in plural form , such as items, cars
Module names (Models) need to be capitalized, and use singular mode, such as Item, Car
Controllers (Controllers) need to be capitalized, use plural form and add "Controller" to the name, Such as ItemsController, CarsController
Views (Views) use plural form, and add behaviors as files at the end, such as: items/view.php, cars/buy.php
上述的一些规则是为了能在程序钟更好的进行互相的调用。接下来就开始真正的编码了。
第一步将所有的的请求都重定向到public目录下,解决方案是在todo文件下添加一个.htaccesss文件,文件内容为:
<IfModule mod_rewrite.c> RewriteEngine on RewriteRule ^$ public/ [L] RewriteRule (.*) public/$1 [L] </IfModule>
在我们把所有的请求都重定向到public目录下以后,我们就需要将所有的数据请求都再重定向到public下的index.php文件,于是就需要在public文件夹下也新建一个.htaccess文件,文件内容为:
<IfModule mod_rewrite.c> RewriteEngine On #如果文件存在就直接访问目录不进行RewriteRule RewriteCond %{REQUEST_FILENAME} !-f #如果目录存在就直接访问目录不进行RewriteRule RewriteCond %{REQUEST_FILENAME} !-d #将所有其他URL重写到 index.php/URL RewriteRule ^(.*)$ index.php?url=$1 [PT,L] </IfModule>
这么做的主要原因有:
可以使程序有一个单一的入口,将所有除静态程序以外的程序都重定向到index.php上;
可以用来生成利于SEO的URL,想要更好的配置URL,后期可能会需要URL路由,这里先不做介绍了。
做完上面的操作,就应该知道我们需要做什么了,没错!在public目录下添加index.php文件,文件内容为:
<?php define('DS',DIRECTORY_SEPARATOR); define('ROOT',dirname(dirname(__FILE__))); $url = $_GET['url']; require_once(ROOT.DS.'library'.DS.'bootstrap.php');
注意上面的PHP代码中,并没有添加PHP结束符号”?>”,这么做的主要原因是:对于只包含PHP代码的文件,结束标志(“?>”)最好不存在,PHP自身并不需要结束符号,不添加结束符号可以很大程度上防止末尾被添加额外的注入内容,让程序更加安全。
在index.php中,我们对library文件夹下的bootstrap.php发起了请求,那么bootstrap.php这个启动文件中到底会包含哪些内容呢?
<?php require_once(ROOT.DS.'config'.DS .'config.php'); require_once(ROOT.DS.'library'.DS .'shared.php');
以上文件都可以直接在index.php文件中引用,我们这么做的原因是为了在后期管理和拓展中更加的方便,所以把需要在一开始的时候就加载运行的程序统一放到一个单独的文件中引用。
先来看看config文件下的config .php文件,该文件的主要作用是设置一些程序的配置项及数据库连接等,主要内容为:
<?php # 设置是否为开发状态 define('DEVELOPMENT_ENVIRONMENT',true); # 设置数据库连接所需数据 define('DB_HOST','localhost'); define('DB_NAME','todo'); define('DB_USER','root'); define('DB_PASSWORD','root');
应该说config.php涉及到的内容并不多,不过是一些基础数据的一些设置,再来看看library下的共用文件shared.php应该怎么写。
<?php /* 检查是否为开发环境并设置是否记录错误日志 */ function setReporting(){ if (DEVELOPMENT_ENVIRONMENT == 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',ROOT.DS. 'tmp' .DS. 'logs' .DS. 'error.log'); } } /* 检测敏感字符转义(Magic Quotes)并移除他们 */ function stripSlashDeep($value){ $value = is_array($value) ? array_map('stripSlashDeep',$value) : stripslashes($value); return $value; } function removeMagicQuotes(){ if (get_magic_quotes_gpc()) { $_GET = stripSlashDeep($_GET); $_POST = stripSlashDeep($_POST); $_COOKIE = stripSlashDeep($_COOKIE); } } /* 检测全局变量设置(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]); } } } } } /* 主请求方法,主要目的拆分URL请求 */ function callHook() { global $url; $urlArray = array(); $urlArray = explode("/",$url); $controller = $urlArray[0]; array_shift($urlArray); $action = $urlArray[0]; array_shift($urlArray); $queryString = $urlArray; $controllerName = $controller; $controller = ucwords($controller); $model = rtrim($controller, 's'); $controller .= 'Controller'; $dispatch = new $controller($model,$controllerName,$action); if ((int)method_exists($controller, $action)) { call_user_func_array(array($dispatch,$action),$queryString); } else { /* 生成错误代码 */ } } /* 自动加载控制器和模型 */ function __autoload($className) { if (file_exists(ROOT . DS . 'library' . DS . strtolower($className) . '.class.php')) { require_once(ROOT . DS . 'library' . DS . strtolower($className) . '.class.php'); } else if (file_exists(ROOT . DS . 'application' . DS . 'controllers' . DS . strtolower($className) . '.php')) { require_once(ROOT . DS . 'application' . DS . 'controllers' . DS . strtolower($className) . '.php'); } else if (file_exists(ROOT . DS . 'application' . DS . 'models' . DS . strtolower($className) . '.php')) { require_once(ROOT . DS . 'application' . DS . 'models' . DS . strtolower($className) . '.php'); } else { /* 生成错误代码 */ } } setReporting(); removeMagicQuotes(); unregisterGlobals(); callHook();
接下来的操作就是在library中建立程序所需要的基类,包括控制器、模型和视图的基类。
新建控制器基类为controller.class.php,控制器的主要功能就是总调度,具体具体内容如下:
<?php class Controller { protected $_model; protected $_controller; protected $_action; protected $_template; function __construct($model, $controller,$action) { $this->_controller = $controller; $this->_action = $action; $this->_model = $model; $this->$model =& new $model; $this->_template =& new Template($controller,$action); } function set($name,$value) { $this->_template->set($name,$value); } function __destruct() { $this->_template->render(); } }
新建控制器基类为model.class.php,考虑到模型需要对数据库进行处理,所以可以新建一个数据库基类sqlquery.class.php,模型去继承sqlquery.class.php。
新建sqlquery.class.php,代码如下:
<?php class SQLQuery { protected $_dbHandle; protected $_result; /** 连接数据库 **/ function connect($address, $account, $pwd, $name) { $this->_dbHandle = @mysql_connect($address, $account, $pwd); if ($this->_dbHandle != 0) { if (mysql_select_db($name, $this->_dbHandle)) { return 1; }else { return 0; } }else { return 0; } } /** 中断数据库连接 **/ function disconnect() { if (@mysql_close($this->_dbHandle) != 0) { return 1; } else { return 0; } } /** 查询所有数据表内容 **/ function selectAll() { $query = 'select * from `'.$this->_table.'`'; return $this->query($query); } /** 查询数据表指定列内容 **/ function select($id) { $query = 'select * from `'.$this->_table.'` where `id` = \''.mysql_real_escape_string($id).'\''; return $this->query($query, 1); } /** 自定义SQL查询语句 **/ function query($query, $singleResult = 0) { $this->_result = mysql_query($query, $this->_dbHandle); if (preg_match("/select/i",$query)) { $result = array(); $table = array(); $field = array(); $tempResults = array(); $numOfFields = mysql_num_fields($this->_result); for ($i = 0; $i < $numOfFields; ++$i) { array_push($table,mysql_field_table($this->_result, $i)); array_push($field,mysql_field_name($this->_result, $i)); } while ($row = mysql_fetch_row($this->_result)) { for ($i = 0;$i < $numOfFields; ++$i) { $table[$i] = trim(ucfirst($table[$i]),"s"); $tempResults[$table[$i]][$field[$i]] = $row[$i]; } if ($singleResult == 1) { mysql_free_result($this->_result); return $tempResults; } array_push($result,$tempResults); } mysql_free_result($this->_result); return($result); } } /** 返回结果集行数 **/ function getNumRows() { return mysql_num_rows($this->_result); } /** 释放结果集内存 **/ function freeResult() { mysql_free_result($this->_result); } /** 返回MySQL操作错误信息 **/ function getError() { return mysql_error($this->_dbHandle); } }
新建model.class.php,代码如下:
<?php class Model extends SQLQuery{ protected $_model; function __construct() { $this->connect(DB_HOST,DB_USER,DB_PASSWORD,DB_NAME); $this->_model = get_class($this); $this->_table = strtolower($this->_model)."s"; } function __destruct() { } }
新建视图基类为template.class.php,具体代码如下:
<?php class Template { protected $variables = array(); protected $_controller; protected $_action; function __construct($controller,$action) { $this->_controller = $controller; $this->_action =$action; } /* 设置变量 */ function set($name,$value) { $this->variables[$name] = $value; } /* 显示模板 */ function render() { extract($this->variables); if (file_exists(ROOT.DS. 'application' .DS. 'views' .DS. $this->_controller .DS. 'header.php')) { include(ROOT.DS. 'application' .DS. 'views' .DS. $this->_controller .DS. 'header.php'); } else { include(ROOT.DS. 'application' .DS. 'views' .DS. 'header.php'); } include (ROOT.DS. 'application' .DS. 'views' .DS. $this->_controller .DS. $this->_action . '.php'); if (file_exists(ROOT.DS. 'application' .DS. 'views' .DS. $this->_controller .DS. 'footer.php')) { include (ROOT.DS. 'application' .DS. 'views' .DS. $this->_controller .DS. 'footer.php'); } else { include (ROOT.DS. 'application' .DS. 'views' .DS. 'footer.php'); } } }
做完了以上这么多操作,基本上整个MVC框架已经出来了,下面就该制作我们的站点了。我们要做的站点其实很简单,一个ToDo程序。
首先是在我们的/application/controller/ 目录下面新建一个站点控制器类为ItemsController,命名为itemscontroller.php,内容为:
<?php class ItemsController extends Controller { function view($id = null,$name = null) { $this->set('title',$name.' - My Todo List App'); $this->set('todo',$this->Item->select($id)); } function viewall() { $this->set('title','All Items - My Todo List App'); $this->set('todo',$this->Item->selectAll()); } function add() { $todo = $_POST['todo']; $this->set('title','Success - My Todo List App'); $this->set('todo',$this->Item->query('insert into items (item_name) values (\''.mysql_real_escape_string($todo).'\')')); } function delete($id) { $this->set('title','Success - My Todo List App'); $this->set('todo',$this->Item->query('delete from items where id = \''.mysql_real_escape_string($id).'\'')); } }
接下来就是先建站点的模型,在我们的/application/model/ 目录下面先建一个站点模型类为Item,内容直接继承Model,代码如下:
<?php class Item extends Model { }
最后一步是设置我们站点的视图部分,我们现在/application/views/目录下新建一个items的文件夹,再在items文件夹下建立与控制器重Action相同的文件,分别为view.php,viewall.php,add.php,delete.php,考虑到这么页面中可能需要共用页首和页尾,所以再新建两个文件,命名为header.php,footer.php,每个文件的代码如下:
view.php文件:查看单条待处理事务
<h2><?php echo $todo['Item']['item_name']?></h2> <a href="../../../items/delete/<?php echo $todo['Item']['id']?>"> <span>Delete this item</span> </a>
viewall.php文件:查看所有待处理事务
<form action="../items/add" method="post"> <input type="text" value="I have to..." onclick="this.value=''" name="todo"> <input type="submit" value="add"> </form> <br/><br/> <?php $number = 0?> <?php foreach ($todo as $todoitem):?> <a href="../items/view/<?php echo $todoitem['Item']['id']?>/<?php echo strtolower(str_replace(" ","-",$todoitem['Item']['item_name']))?>"> <span> <?php echo ++$number?> <?php echo $todoitem['Item']['item_name']?> </span> </a><br/> <?php endforeach?>
add.php文件:添加待处理事务
<a href="../items/viewall">Todo successfully added. Click here to go back.</a><br/>
delete.php文件:删除事务
<a href="../../items/viewall">Todo successfully deleted. Click here to go back.</a><br/>
header.php:页首文件
<html> <head> <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:#222222;font-family:georgia,times;font-size:24px;font-weight:normal;line-height:1.2em;color:black;text-decoration:none;} a:hover {background-color:#BCFC3D;} 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 id="My-nbsp-Todo-List-nbsp-App">My Todo-List App</h1>
footer.php:页尾文件
</body> </html>
当然还有一个必不可少的操作就是在数据中中建立一张表,具体代码如下:
CREATE TABLE IF NOT EXISTS `items` ( `id` int(11) NOT NULL AUTO_INCREMENT, `item_name` varchar(255) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=17 ;
至此一个使用MVC开发的网站就开发完成了,你现在可以通过访问http://localhost/todo/items/viewall 查看新建的站点。

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

AI Hentai Generator
Generate AI Hentai for free.

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics



PHP 8.4 brings several new features, security improvements, and performance improvements with healthy amounts of feature deprecations and removals. This guide explains how to install PHP 8.4 or upgrade to PHP 8.4 on Ubuntu, Debian, or their derivati

Visual Studio Code, also known as VS Code, is a free source code editor — or integrated development environment (IDE) — available for all major operating systems. With a large collection of extensions for many programming languages, VS Code can be c

If you are an experienced PHP developer, you might have the feeling that you’ve been there and done that already.You have developed a significant number of applications, debugged millions of lines of code, and tweaked a bunch of scripts to achieve op

This tutorial demonstrates how to efficiently process XML documents using PHP. XML (eXtensible Markup Language) is a versatile text-based markup language designed for both human readability and machine parsing. It's commonly used for data storage an

JWT is an open standard based on JSON, used to securely transmit information between parties, mainly for identity authentication and information exchange. 1. JWT consists of three parts: Header, Payload and Signature. 2. The working principle of JWT includes three steps: generating JWT, verifying JWT and parsing Payload. 3. When using JWT for authentication in PHP, JWT can be generated and verified, and user role and permission information can be included in advanced usage. 4. Common errors include signature verification failure, token expiration, and payload oversized. Debugging skills include using debugging tools and logging. 5. Performance optimization and best practices include using appropriate signature algorithms, setting validity periods reasonably,

A string is a sequence of characters, including letters, numbers, and symbols. This tutorial will learn how to calculate the number of vowels in a given string in PHP using different methods. The vowels in English are a, e, i, o, u, and they can be uppercase or lowercase. What is a vowel? Vowels are alphabetic characters that represent a specific pronunciation. There are five vowels in English, including uppercase and lowercase: a, e, i, o, u Example 1 Input: String = "Tutorialspoint" Output: 6 explain The vowels in the string "Tutorialspoint" are u, o, i, a, o, i. There are 6 yuan in total

Static binding (static::) implements late static binding (LSB) in PHP, allowing calling classes to be referenced in static contexts rather than defining classes. 1) The parsing process is performed at runtime, 2) Look up the call class in the inheritance relationship, 3) It may bring performance overhead.

What are the magic methods of PHP? PHP's magic methods include: 1.\_\_construct, used to initialize objects; 2.\_\_destruct, used to clean up resources; 3.\_\_call, handle non-existent method calls; 4.\_\_get, implement dynamic attribute access; 5.\_\_set, implement dynamic attribute settings. These methods are automatically called in certain situations, improving code flexibility and efficiency.
