search
HomeBackend DevelopmentPHP TutorialUse 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).

Use php to build your own mvc framework

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.

Use php to build your own mvc framework

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(&#39;DS&#39;,DIRECTORY_SEPARATOR);
    define(&#39;ROOT&#39;,dirname(dirname(__FILE__)));
    $url = $_GET[&#39;url&#39;];
    require_once(ROOT.DS.&#39;library&#39;.DS.&#39;bootstrap.php&#39;);

注意上面的PHP代码中,并没有添加PHP结束符号”?>”,这么做的主要原因是:对于只包含PHP代码的文件,结束标志(“?>”)最好不存在,PHP自身并不需要结束符号,不添加结束符号可以很大程度上防止末尾被添加额外的注入内容,让程序更加安全。

在index.php中,我们对library文件夹下的bootstrap.php发起了请求,那么bootstrap.php这个启动文件中到底会包含哪些内容呢?

<?php
    require_once(ROOT.DS.&#39;config&#39;.DS .&#39;config.php&#39;);
    require_once(ROOT.DS.&#39;library&#39;.DS .&#39;shared.php&#39;);

以上文件都可以直接在index.php文件中引用,我们这么做的原因是为了在后期管理和拓展中更加的方便,所以把需要在一开始的时候就加载运行的程序统一放到一个单独的文件中引用。

先来看看config文件下的config .php文件,该文件的主要作用是设置一些程序的配置项及数据库连接等,主要内容为:

<?php
    # 设置是否为开发状态
    define(&#39;DEVELOPMENT_ENVIRONMENT&#39;,true);
    # 设置数据库连接所需数据
    define(&#39;DB_HOST&#39;,&#39;localhost&#39;);
    define(&#39;DB_NAME&#39;,&#39;todo&#39;);
    define(&#39;DB_USER&#39;,&#39;root&#39;);
    define(&#39;DB_PASSWORD&#39;,&#39;root&#39;);

应该说config.php涉及到的内容并不多,不过是一些基础数据的一些设置,再来看看library下的共用文件shared.php应该怎么写。

<?php
    /* 检查是否为开发环境并设置是否记录错误日志 */
    function setReporting(){
        if (DEVELOPMENT_ENVIRONMENT == true) {
            error_reporting(E_ALL);
            ini_set(&#39;display_errors&#39;,&#39;On&#39;);
        } else {
            error_reporting(E_ALL);
            ini_set(&#39;display_errors&#39;,&#39;Off&#39;);
            ini_set(&#39;log_errors&#39;,&#39;On&#39;);
            ini_set(&#39;error_log&#39;,ROOT.DS. &#39;tmp&#39; .DS. &#39;logs&#39; .DS. &#39;error.log&#39;);
        }
    }
    /* 检测敏感字符转义(Magic Quotes)并移除他们 */
    function stripSlashDeep($value){
    $value = is_array($value) ? array_map(&#39;stripSlashDeep&#39;,$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(&#39;register_globals&#39;)) {
           $array = array(&#39;_SESSION&#39;,&#39;_POST&#39;,&#39;_GET&#39;,&#39;_COOKIE&#39;,&#39;_REQUEST&#39;,&#39;_SERVER&#39;,&#39;_ENV&#39;,&#39;_FILES&#39;);
           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, &#39;s&#39;);
        $controller .= &#39;Controller&#39;;
        $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 . &#39;library&#39; . DS . strtolower($className) . &#39;.class.php&#39;)) {
            require_once(ROOT . DS . &#39;library&#39; . DS . strtolower($className) . &#39;.class.php&#39;);
        } else if (file_exists(ROOT . DS . &#39;application&#39; . DS . &#39;controllers&#39; . DS . strtolower($className) . &#39;.php&#39;)) {
            require_once(ROOT . DS . &#39;application&#39; . DS . &#39;controllers&#39; . DS . strtolower($className) . &#39;.php&#39;);
        } else if (file_exists(ROOT . DS . &#39;application&#39; . DS . &#39;models&#39; . DS . strtolower($className) . &#39;.php&#39;)) {
            require_once(ROOT . DS . &#39;application&#39; . DS . &#39;models&#39; . DS . strtolower($className) . &#39;.php&#39;);
        } 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 = &#39;select * from `&#39;.$this->_table.&#39;`&#39;;
            return $this->query($query);
        }
        /** 查询数据表指定列内容 **/
        function select($id) {
            $query = &#39;select * from `&#39;.$this->_table.&#39;` where `id` = \&#39;&#39;.mysql_real_escape_string($id).&#39;\&#39;&#39;;
            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. &#39;application&#39; .DS. &#39;views&#39; .DS. $this->_controller .DS. &#39;header.php&#39;)) {
               include(ROOT.DS. &#39;application&#39; .DS. &#39;views&#39; .DS. $this->_controller .DS. &#39;header.php&#39;);
           } else {
               include(ROOT.DS. &#39;application&#39; .DS. &#39;views&#39; .DS. &#39;header.php&#39;);
           }
           include (ROOT.DS. &#39;application&#39; .DS. &#39;views&#39; .DS. $this->_controller .DS. $this->_action . &#39;.php&#39;);
           if (file_exists(ROOT.DS. &#39;application&#39; .DS. &#39;views&#39; .DS. $this->_controller .DS. &#39;footer.php&#39;)) {
               include (ROOT.DS. &#39;application&#39; .DS. &#39;views&#39; .DS. $this->_controller .DS. &#39;footer.php&#39;);
           } else {
               include (ROOT.DS. &#39;application&#39; .DS. &#39;views&#39; .DS. &#39;footer.php&#39;);
           }
        }
    }

做完了以上这么多操作,基本上整个MVC框架已经出来了,下面就该制作我们的站点了。我们要做的站点其实很简单,一个ToDo程序。

首先是在我们的/application/controller/ 目录下面新建一个站点控制器类为ItemsController,命名为itemscontroller.php,内容为:

<?php
    class ItemsController extends Controller {
       function view($id = null,$name = null) {
           $this->set(&#39;title&#39;,$name.&#39; - My Todo List App&#39;);
           $this->set(&#39;todo&#39;,$this->Item->select($id));
       }
       function viewall() {
           $this->set(&#39;title&#39;,&#39;All Items - My Todo List App&#39;);
           $this->set(&#39;todo&#39;,$this->Item->selectAll());
       }
       function add() {
           $todo = $_POST[&#39;todo&#39;];
           $this->set(&#39;title&#39;,&#39;Success - My Todo List App&#39;);
           $this->set(&#39;todo&#39;,$this->Item->query(&#39;insert into items (item_name) values (\&#39;&#39;.mysql_real_escape_string($todo).&#39;\&#39;)&#39;));
       }
       function delete($id) {
           $this->set(&#39;title&#39;,&#39;Success - My Todo List App&#39;);
           $this->set(&#39;todo&#39;,$this->Item->query(&#39;delete from items where id = \&#39;&#39;.mysql_real_escape_string($id).&#39;\&#39;&#39;));
       }
    }

接下来就是先建站点的模型,在我们的/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[&#39;Item&#39;][&#39;item_name&#39;]?></h2>
<a href="../../../items/delete/<?php echo $todo[&#39;Item&#39;][&#39;id&#39;]?>">
<span>Delete this item</span>
</a>

viewall.php文件:查看所有待处理事务

<form action="../items/add" method="post">
    <input type="text" value="I have to..." onclick="this.value=&#39;&#39;" 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[&#39;Item&#39;][&#39;id&#39;]?>/<?php echo strtolower(str_replace(" ","-",$todoitem[&#39;Item&#39;][&#39;item_name&#39;]))?>">
        <span>
            <?php echo ++$number?>
            <?php echo $todoitem[&#39;Item&#39;][&#39;item_name&#39;]?>
        </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 查看新建的站点。


Statement
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
PHP's Purpose: Building Dynamic WebsitesPHP's Purpose: Building Dynamic WebsitesApr 15, 2025 am 12:18 AM

PHP is used to build dynamic websites, and its core functions include: 1. Generate dynamic content and generate web pages in real time by connecting with the database; 2. Process user interaction and form submissions, verify inputs and respond to operations; 3. Manage sessions and user authentication to provide a personalized experience; 4. Optimize performance and follow best practices to improve website efficiency and security.

PHP: Handling Databases and Server-Side LogicPHP: Handling Databases and Server-Side LogicApr 15, 2025 am 12:15 AM

PHP uses MySQLi and PDO extensions to interact in database operations and server-side logic processing, and processes server-side logic through functions such as session management. 1) Use MySQLi or PDO to connect to the database and execute SQL queries. 2) Handle HTTP requests and user status through session management and other functions. 3) Use transactions to ensure the atomicity of database operations. 4) Prevent SQL injection, use exception handling and closing connections for debugging. 5) Optimize performance through indexing and cache, write highly readable code and perform error handling.

How do you prevent SQL Injection in PHP? (Prepared statements, PDO)How do you prevent SQL Injection in PHP? (Prepared statements, PDO)Apr 15, 2025 am 12:15 AM

Using preprocessing statements and PDO in PHP can effectively prevent SQL injection attacks. 1) Use PDO to connect to the database and set the error mode. 2) Create preprocessing statements through the prepare method and pass data using placeholders and execute methods. 3) Process query results and ensure the security and performance of the code.

PHP and Python: Code Examples and ComparisonPHP and Python: Code Examples and ComparisonApr 15, 2025 am 12:07 AM

PHP and Python have their own advantages and disadvantages, and the choice depends on project needs and personal preferences. 1.PHP is suitable for rapid development and maintenance of large-scale web applications. 2. Python dominates the field of data science and machine learning.

PHP in Action: Real-World Examples and ApplicationsPHP in Action: Real-World Examples and ApplicationsApr 14, 2025 am 12:19 AM

PHP is widely used in e-commerce, content management systems and API development. 1) E-commerce: used for shopping cart function and payment processing. 2) Content management system: used for dynamic content generation and user management. 3) API development: used for RESTful API development and API security. Through performance optimization and best practices, the efficiency and maintainability of PHP applications are improved.

PHP: Creating Interactive Web Content with EasePHP: Creating Interactive Web Content with EaseApr 14, 2025 am 12:15 AM

PHP makes it easy to create interactive web content. 1) Dynamically generate content by embedding HTML and display it in real time based on user input or database data. 2) Process form submission and generate dynamic output to ensure that htmlspecialchars is used to prevent XSS. 3) Use MySQL to create a user registration system, and use password_hash and preprocessing statements to enhance security. Mastering these techniques will improve the efficiency of web development.

PHP and Python: Comparing Two Popular Programming LanguagesPHP and Python: Comparing Two Popular Programming LanguagesApr 14, 2025 am 12:13 AM

PHP and Python each have their own advantages, and choose according to project requirements. 1.PHP is suitable for web development, especially for rapid development and maintenance of websites. 2. Python is suitable for data science, machine learning and artificial intelligence, with concise syntax and suitable for beginners.

The Enduring Relevance of PHP: Is It Still Alive?The Enduring Relevance of PHP: Is It Still Alive?Apr 14, 2025 am 12:12 AM

PHP is still dynamic and still occupies an important position in the field of modern programming. 1) PHP's simplicity and powerful community support make it widely used in web development; 2) Its flexibility and stability make it outstanding in handling web forms, database operations and file processing; 3) PHP is constantly evolving and optimizing, suitable for beginners and experienced developers.

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
4 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Best Graphic Settings
4 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. How to Fix Audio if You Can't Hear Anyone
4 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
WWE 2K25: How To Unlock Everything In MyRise
1 months agoBy尊渡假赌尊渡假赌尊渡假赌

Hot Tools

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

MantisBT

MantisBT

Mantis is an easy-to-deploy web-based defect tracking tool designed to aid in product defect tracking. It requires PHP, MySQL and a web server. Check out our demo and hosting services.

PhpStorm Mac version

PhpStorm Mac version

The latest (2018.2.1) professional PHP integrated development tool

WebStorm Mac version

WebStorm Mac version

Useful JavaScript development tools

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

Powerful PHP integrated development environment