mvc模式(model-view-controller)是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(model)、视图(view)和控制器(controller)。
PHP中MVC模式也称Web MVC,从上世纪70年代进化而来。MVC的目的是实现一种动态的程序设计,便于后续对程序的修改和扩展简化,并且使程序某一部分的重复利用成为可能。除 此之外,此模式通过对复杂度的简化,使程序结构更加直观。软件系统通过对自身基本部份分离的同时,也赋予了各个基本部分应有的功能。
MVC各部分的职能:

一个典型的Web MVC流程:
立即进入“豆包AI人工智官网入口”;
立即学习“豆包AI人工智能在线问答入口”;
网络上有大量优秀的MVC框架可供使用,本教程并不是为了开发一个全面的、终极的MVC框架解决方案,而是将它看作是一个很好的从内部学习PHP的机会,在此过程中,你将学习面向对象编程和MVC设计模式,并学习到开发中的一些注意事项。
更重要的是,你可以完全控制你的框架,并将你的想法融入到你开发的框架中。虽然不一定是做好的,但是你可以按照你的方式去开发功能和模块。
在开始开发前,让我们先来把项目建立好,假设我们建立的项目为 todo,MVC的框架可以命名为 FastPHP,那么接下来的第一步就是把目录结构先设置好。

虽然在这个教程中不会使用到上面的所有的目录,但是为了以后程序的可拓展性,在一开始就把程序目录设置好使非常必要的。下面就具体说说每个目录的作用:
在目录设置好以后,我们接下来就要来规定一下代码的规范:
上述的一些规则是为了能在程序中更好的进行互相的调用。接下来就开始真正的PHP MVC编程了。
将所有的数据请求都重定向 index.php 文件,在 todo 目录下新建一个 .htaccess 文件,文件内容为:
<span class="hljs-section"><IfModule mod_rewrite.c>
<span class="hljs-attribute"><span class="hljs-nomarkup">RewriteEngine <span class="hljs-literal">On
<span class="hljs-comment"># 确保请求路径不是一个文件名或目录
<span class="hljs-attribute"><span class="hljs-nomarkup">RewriteCond <span class="hljs-variable">%{REQUEST_FILENAME} !-f
<span class="hljs-attribute"><span class="hljs-nomarkup">RewriteCond <span class="hljs-variable">%{REQUEST_FILENAME} !-d
<span class="hljs-comment"># 重定向所有请求到 index.php?url=PATHNAME
<span class="hljs-attribute"><span class="hljs-nomarkup">RewriteRule ^(.*)$ index.php?url=<span class="hljs-number">$1<span class="hljs-meta"> [PT,L]
<span class="hljs-section"></IfModule>
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>做完上面的操作,就应该知道我们需要做什么了,没错!在 public 目录下添加 index.php 文件,文件内容为:
<span class="php"><span class="hljs-meta"><?php <span class="hljs-comment">// 应用目录为当前目录 define(<span class="hljs-string">'APP_PATH', <span class="hljs-keyword">__DIR__.<span class="hljs-string">'/'); <span class="hljs-comment">// 开启调试模式 define(<span class="hljs-string">'APP_DEBUG', <span class="hljs-keyword">true); <span class="hljs-comment">// 网站根URL define(<span class="hljs-string">'APP_URL', <span class="hljs-string">'http://localhost/fastphp'); <span class="hljs-comment">// 加载框架 <span class="hljs-keyword">require <span class="hljs-string">'./fastphp/FastPHP.php'; </span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
在 index.php 中,我们对 fastphp 文件夹下的 FastPHP.php 发起了请求,那么 FastPHP.php 这个启动文件中到底会包含哪些内容呢?
<span class="php"><span class="hljs-meta"><?php <span class="hljs-comment">// 初始化常量 defined(<span class="hljs-string">'FRAME_PATH') <span class="hljs-keyword">or define(<span class="hljs-string">'FRAME_PATH', <span class="hljs-keyword">__DIR__.<span class="hljs-string">'/'); defined(<span class="hljs-string">'APP_PATH') <span class="hljs-keyword">or define(<span class="hljs-string">'APP_PATH', dirname($_SERVER[<span class="hljs-string">'SCRIPT_FILENAME']).<span class="hljs-string">'/'); defined(<span class="hljs-string">'APP_DEBUG') <span class="hljs-keyword">or define(<span class="hljs-string">'APP_DEBUG', <span class="hljs-keyword">false); defined(<span class="hljs-string">'CONFIG_PATH') <span class="hljs-keyword">or define(<span class="hljs-string">'CONFIG_PATH', APP_PATH.<span class="hljs-string">'config/'); defined(<span class="hljs-string">'RUNTIME_PATH') <span class="hljs-keyword">or define(<span class="hljs-string">'RUNTIME_PATH', APP_PATH.<span class="hljs-string">'runtime/'); <span class="hljs-comment">// 包含配置文件 <span class="hljs-keyword">require APP_PATH . <span class="hljs-string">'config/config.php'; <span class="hljs-comment">//包含核心框架类 <span class="hljs-keyword">require FRAME_PATH . <span class="hljs-string">'Core.php'; <span class="hljs-comment">// 实例化核心类 $fast = <span class="hljs-keyword">new Core; $fast->run(); </span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
先来看看config文件下的 config .php 文件,该文件的主要作用是设置一些程序的配置项及数据库连接等,主要内容为:
<span class="php"><span class="hljs-meta"><?php <span class="hljs-comment">/** 变量配置 **/ define(<span class="hljs-string">'DB_NAME', <span class="hljs-string">'todo'); define(<span class="hljs-string">'DB_USER', <span class="hljs-string">'root'); define(<span class="hljs-string">'DB_PASSWORD', <span class="hljs-string">'root'); define(<span class="hljs-string">'DB_HOST', <span class="hljs-string">'localhost'); </span></span></span></span></span></span></span></span></span></span></span>
<span class="php"><span class="hljs-meta"><?php
<span class="hljs-comment">/**
* FastPHP核心框架
*/
<span class="hljs-class"><span class="hljs-keyword">class <span class="hljs-title">Core
{
<span class="hljs-comment">// 运行程序
<span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">run<span class="hljs-params">()
{
spl_autoload_register(<span class="hljs-keyword">array($this, <span class="hljs-string">'loadClass'));
$this->setReporting();
$this->removeMagicQuotes();
$this->unregisterGlobals();
$this->Route();
}
<span class="hljs-comment">// 路由处理
<span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">Route<span class="hljs-params">()
{
$controllerName = <span class="hljs-string">'Index';
$action = <span class="hljs-string">'index';
<span class="hljs-keyword">if (!<span class="hljs-keyword">empty($_GET[<span class="hljs-string">'url'])) {
$url = $_GET[<span class="hljs-string">'url'];
$urlArray = explode(<span class="hljs-string">'/', $url);
<span class="hljs-comment">// 获取控制器名
$controllerName = ucfirst($urlArray[<span class="hljs-number">0]);
<span class="hljs-comment">// 获取动作名
array_shift($urlArray);
$action = <span class="hljs-keyword">empty($urlArray[<span class="hljs-number">0]) ? <span class="hljs-string">'index' : $urlArray[<span class="hljs-number">0];
<span class="hljs-comment">//获取URL参数
array_shift($urlArray);
$queryString = <span class="hljs-keyword">empty($urlArray) ? <span class="hljs-keyword">array() : $urlArray;
}
<span class="hljs-comment">// 数据为空的处理
$queryString = <span class="hljs-keyword">empty($queryString) ? <span class="hljs-keyword">array() : $queryString;
<span class="hljs-comment">// 实例化控制器
$controller = $controllerName . <span class="hljs-string">'Controller';
$dispatch = <span class="hljs-keyword">new $controller($controllerName, $action);
<span class="hljs-comment">// 如果控制器存和动作存在,这调用并传入URL参数
<span class="hljs-keyword">if ((int)method_exists($controller, $action)) {
call_user_func_array(<span class="hljs-keyword">array($dispatch, $action), $queryString);
} <span class="hljs-keyword">else {
<span class="hljs-keyword">exit($controller . <span class="hljs-string">"控制器不存在");
}
}
<span class="hljs-comment">// 检测开发环境
<span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">setReporting<span class="hljs-params">()
{
<span class="hljs-keyword">if (APP_DEBUG === <span class="hljs-keyword">true) {
error_reporting(E_ALL);
ini_set(<span class="hljs-string">'display_errors',<span class="hljs-string">'On');
} <span class="hljs-keyword">else {
error_reporting(E_ALL);
ini_set(<span class="hljs-string">'display_errors',<span class="hljs-string">'Off');
ini_set(<span class="hljs-string">'log_errors', <span class="hljs-string">'On');
ini_set(<span class="hljs-string">'error_log', RUNTIME_PATH. <span class="hljs-string">'logs/error.log');
}
}
<span class="hljs-comment">// 删除敏感字符
<span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">stripSlashesDeep<span class="hljs-params">($value)
{
$value = is_array($value) ? array_map(<span class="hljs-string">'stripSlashesDeep', $value) : stripslashes($value);
<span class="hljs-keyword">return $value;
}
<span class="hljs-comment">// 检测敏感字符并删除
<span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">removeMagicQuotes<span class="hljs-params">()
{
<span class="hljs-keyword">if ( get_magic_quotes_gpc()) {
$_GET = stripSlashesDeep($_GET );
$_POST = stripSlashesDeep($_POST );
$_COOKIE = stripSlashesDeep($_COOKIE);
$_SESSION = stripSlashesDeep($_SESSION);
}
}
<span class="hljs-comment">// 检测自定义全局变量(register globals)并移除
<span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">unregisterGlobals<span class="hljs-params">()
{
<span class="hljs-keyword">if (ini_get(<span class="hljs-string">'register_globals')) {
$array = <span class="hljs-keyword">array(<span class="hljs-string">'_SESSION', <span class="hljs-string">'_POST', <span class="hljs-string">'_GET', <span class="hljs-string">'_COOKIE', <span class="hljs-string">'_REQUEST', <span class="hljs-string">'_SERVER', <span class="hljs-string">'_ENV', <span class="hljs-string">'_FILES');
<span class="hljs-keyword">foreach ($array <span class="hljs-keyword">as $value) {
<span class="hljs-keyword">foreach ($GLOBALS[$value] <span class="hljs-keyword">as $key => $var) {
<span class="hljs-keyword">if ($var === $GLOBALS[$key]) {
<span class="hljs-keyword">unset($GLOBALS[$key]);
}
}
}
}
}
<span class="hljs-comment">// 自动加载控制器和模型类
<span class="hljs-keyword">static <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">loadClass<span class="hljs-params">($class)
{
$frameworks = FRAME_PATH . $class . <span class="hljs-string">'.class.php';
$controllers = APP_PATH . <span class="hljs-string">'application/controllers/' . $class . <span class="hljs-string">'.class.php';
$models = APP_PATH . <span class="hljs-string">'application/models/' . $class . <span class="hljs-string">'.class.php';
<span class="hljs-keyword">if (file_exists($frameworks)) {
<span class="hljs-comment">// 加载框架核心类
<span class="hljs-keyword">include $frameworks;
} <span class="hljs-keyword">elseif (file_exists($controllers)) {
<span class="hljs-comment">// 加载应用控制器类
<span class="hljs-keyword">include $controllers;
} <span class="hljs-keyword">elseif (file_exists($models)) {
<span class="hljs-comment">//加载应用模型类
<span class="hljs-keyword">include $models;
} <span class="hljs-keyword">else {
<span class="hljs-comment">/* 错误代码 */
}
}
}
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>下面重点讲解主请求方法 callHook(),首先我们想看看我们的 URL 会这样:
yoursite.com/controllerName/actionName/queryString
callHook()的作用就是,从全局变量 $_GET['url']变量中获取 URL,并将其分割成三部分:$controller、$action 和 $queryString。
例如,URL链接为:todo.com/item/view/1/first-item,那么
分割完成后,会实例化一个新的控制器:$controller.'Controller'(其中“.”是连字符),并调用其方法 $action。
接下来的操作就是在 fastphp 中建立程序所需的基类,包括控制器、模型和视图的基类。
新建控制器基类为 Controller.class.php,控制器的主要功能就是总调度,具体具体内容如下:
<span class="php"><span class="hljs-meta"><?php
<span class="hljs-comment">/**
* 控制器基类
*/
<span class="hljs-class"><span class="hljs-keyword">class <span class="hljs-title">Controller
{
<span class="hljs-keyword">protected $_controller;
<span class="hljs-keyword">protected $_action;
<span class="hljs-keyword">protected $_view;
<span class="hljs-comment">// 构造函数,初始化属性,并实例化对应模型
<span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">__construct<span class="hljs-params">($controller, $action)
{
$this->_controller = $controller;
$this->_action = $action;
$this->_view = <span class="hljs-keyword">new View($controller, $action);
}
<span class="hljs-comment">// 分配变量
<span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">assign<span class="hljs-params">($name, $value)
{
$this->_view->assign($name, $value);
}
<span class="hljs-comment">// 渲染视图
<span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">__destruct<span class="hljs-params">()
{
$this->_view->render();
}
}
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>Controller 类实现所有控制器、模型和视图(View类)的通信。在执行析构函数时,我们可以调用 render() 来显示视图(view)文件。
新建模型基类为 Model.class.php,模型基类 Model.class.php 代码如下:
<span class="php"><span class="hljs-meta"><?php
<span class="hljs-class"><span class="hljs-keyword">class <span class="hljs-title">Model <span class="hljs-keyword">extends <span class="hljs-title">Sql
{
<span class="hljs-keyword">protected $_model;
<span class="hljs-keyword">protected $_table;
<span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">__construct<span class="hljs-params">()
{
<span class="hljs-comment">// 连接数据库
$this->connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
<span class="hljs-comment">// 获取模型名称
$this->_model = get_class($this);
$this->_model = rtrim($this->_model, <span class="hljs-string">'Model');
<span class="hljs-comment">// 数据库表名与类名一致
$this->_table = strtolower($this->_model);
}
<span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">__destruct<span class="hljs-params">()
{
}
}
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>考虑到模型需要对数据库进行处理,所以单独建立一个数据库基类 Sql.class.php,模型基类继承 Sql.class.php,代码如下:
<span class="php"><span class="hljs-meta"><?php
<span class="hljs-class"><span class="hljs-keyword">class <span class="hljs-title">Sql
{
<span class="hljs-keyword">protected $_dbHandle;
<span class="hljs-keyword">protected $_result;
<span class="hljs-comment">// 连接数据库
<span class="hljs-keyword">public <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">connect<span class="hljs-params">($host, $user, $pass, $dbname)
{
<span class="hljs-keyword">try {
$dsn = sprintf(<span class="hljs-string">"mysql:host=%s;dbname=%s;charset=utf8", $host, $dbname);
$this->_dbHandle = <span class="hljs-keyword">new PDO($dsn, $user, $pass, <span class="hljs-keyword">array(PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC));
} <span class="hljs-keyword">catch (PDOException $e) {
<span class="hljs-keyword">exit(<span class="hljs-string">'错误: ' . $e->getMessage());
}
}
<span class="hljs-comment">// 查询所有
<span class="hljs-keyword">public <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">selectAll<span class="hljs-params">()
{
$sql = sprintf(<span class="hljs-string">"select * from `%s`", $this->_table);
$sth = $this->_dbHandle->prepare($sql);
$sth->execute();
<span class="hljs-keyword">return $sth->fetchAll();
}
<span class="hljs-comment">// 根据条件 (id) 查询
<span class="hljs-keyword">public <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">select<span class="hljs-params">($id)
{
$sql = sprintf(<span class="hljs-string">"select * from `%s` where `id` = '%s'", $this->_table, $id);
$sth = $this->_dbHandle->prepare($sql);
$sth->execute();
<span class="hljs-keyword">return $sth->fetch();
}
<span class="hljs-comment">// 根据条件 (id) 删除
<span class="hljs-keyword">public <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">delete<span class="hljs-params">($id)
{
$sql = sprintf(<span class="hljs-string">"delete from `%s` where `id` = '%s'", $this->_table, $id);
$sth = $this->_dbHandle->prepare($sql);
$sth->execute();
<span class="hljs-keyword">return $sth->rowCount();
}
<span class="hljs-comment">// 自定义SQL查询,返回影响的行数
<span class="hljs-keyword">public <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">query<span class="hljs-params">($sql)
{
$sth = $this->_dbHandle->prepare($sql);
$sth->execute();
<span class="hljs-keyword">return $sth->rowCount();
}
<span class="hljs-comment">// 新增数据
<span class="hljs-keyword">public <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">add<span class="hljs-params">($data)
{
$sql = sprintf(<span class="hljs-string">"insert into `%s` %s", $this->_table, $this->formatInsert($data));
<span class="hljs-keyword">return $this->query($sql);
}
<span class="hljs-comment">// 修改数据
<span class="hljs-keyword">public <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">update<span class="hljs-params">($id, $data)
{
$sql = sprintf(<span class="hljs-string">"update `%s` set %s where `id` = '%s'", $this->_table, $this->formatUpdate($data), $id);
<span class="hljs-keyword">return $this->query($sql);
}
<span class="hljs-comment">// 将数组转换成插入格式的sql语句
<span class="hljs-keyword">private <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">formatInsert<span class="hljs-params">($data)
{
$fields = <span class="hljs-keyword">array();
$values = <span class="hljs-keyword">array();
<span class="hljs-keyword">foreach ($data <span class="hljs-keyword">as $key => $value) {
$fields[] = sprintf(<span class="hljs-string">"`%s`", $key);
$values[] = sprintf(<span class="hljs-string">"'%s'", $value);
}
$field = implode(<span class="hljs-string">',', $fields);
$value = implode(<span class="hljs-string">',', $values);
<span class="hljs-keyword">return sprintf(<span class="hljs-string">"(%s) values (%s)", $field, $value);
}
<span class="hljs-comment">// 将数组转换成更新格式的sql语句
<span class="hljs-keyword">private <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">formatUpdate<span class="hljs-params">($data)
{
$fields = <span class="hljs-keyword">array();
<span class="hljs-keyword">foreach ($data <span class="hljs-keyword">as $key => $value) {
$fields[] = sprintf(<span class="hljs-string">"`%s` = '%s'", $key, $value);
}
<span class="hljs-keyword">return implode(<span class="hljs-string">',', $fields);
}
}
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>应该说,Sql.class.php 是框架的核心部分。为什么?因为通过它,我们创建了一个 SQL 抽象层,可以大大减少了数据库的编程工作。虽然 PDO 接口本来已经很简洁,但是抽象之后框架的可灵活性更高。
视图类 View.class.php 内容如下:
<span class="php"><span class="hljs-meta"><?php
<span class="hljs-comment">/**
* 视图基类
*/
<span class="hljs-class"><span class="hljs-keyword">class <span class="hljs-title">View
{
<span class="hljs-keyword">protected $variables = <span class="hljs-keyword">array();
<span class="hljs-keyword">protected $_controller;
<span class="hljs-keyword">protected $_action;
<span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">__construct<span class="hljs-params">($controller, $action)
{
$this->_controller = $controller;
$this->_action = $action;
}
<span class="hljs-comment">/** 分配变量 **/
<span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">assign<span class="hljs-params">($name, $value)
{
$this->variables[$name] = $value;
}
<span class="hljs-comment">/** 渲染显示 **/
<span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">render<span class="hljs-params">()
{
extract($this->variables);
$defaultHeader = APP_PATH . <span class="hljs-string">'application/views/header.php';
$defaultFooter = APP_PATH . <span class="hljs-string">'application/views/footer.php';
$controllerHeader = APP_PATH . <span class="hljs-string">'application/views/' . $this->_controller . <span class="hljs-string">'/header.php';
$controllerFooter = APP_PATH . <span class="hljs-string">'application/views/' . $this->_controller . <span class="hljs-string">'/footer.php';
<span class="hljs-comment">// 页头文件
<span class="hljs-keyword">if (file_exists($controllerHeader)) {
<span class="hljs-keyword">include ($controllerHeader);
} <span class="hljs-keyword">else {
<span class="hljs-keyword">include ($defaultHeader);
}
<span class="hljs-comment">// 页内容文件
<span class="hljs-keyword">include (APP_PATH . <span class="hljs-string">'application/views/' . $this->_controller . <span class="hljs-string">'/' . $this->_action . <span class="hljs-string">'.php');
<span class="hljs-comment">// 页脚文件
<span class="hljs-keyword">if (file_exists($controllerFooter)) {
<span class="hljs-keyword">include ($controllerFooter);
} <span class="hljs-keyword">else {
<span class="hljs-keyword">include ($defaultFooter);
}
}
}
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>这样我们的核心的PHP MVC框架就编写完成了,下面我们开始编写应用来测试框架功能。
在 SQL 中新建一个 todo 数据库,使用下面的语句增加 item 数据表并插入2条记录:
<span class="hljs-keyword">CREATE <span class="hljs-keyword">DATABASE <span class="hljs-string">`todo` <span class="hljs-keyword">DEFAULT <span class="hljs-built_in">CHARACTER <span class="hljs-keyword">SET utf8 <span class="hljs-keyword">COLLATE utf8_general_ci;
<span class="hljs-keyword">USE <span class="hljs-string">`todo`;
<span class="hljs-keyword">CREATE <span class="hljs-keyword">TABLE <span class="hljs-string">`item` (
<span class="hljs-string">`id` <span class="hljs-built_in">int(<span class="hljs-number">11) <span class="hljs-keyword">NOT <span class="hljs-literal">NULL auto_increment,
<span class="hljs-string">`item_name` <span class="hljs-built_in">varchar(<span class="hljs-number">255) <span class="hljs-keyword">NOT <span class="hljs-literal">NULL,
PRIMARY <span class="hljs-keyword">KEY (<span class="hljs-string">`id`)
) <span class="hljs-keyword">ENGINE=<span class="hljs-keyword">InnoDB AUTO_INCREMENT=<span class="hljs-number">1 <span class="hljs-keyword">DEFAULT <span class="hljs-keyword">CHARSET=utf8;
<span class="hljs-keyword">INSERT <span class="hljs-keyword">INTO <span class="hljs-string">`item` <span class="hljs-keyword">VALUES(<span class="hljs-number">1, <span class="hljs-string">'Hello World.');
<span class="hljs-keyword">INSERT <span class="hljs-keyword">INTO <span class="hljs-string">`item` <span class="hljs-keyword">VALUES(<span class="hljs-number">2, <span class="hljs-string">'Lets go!');</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>然后,我们还需要在 models 目录中创建一个 ItemModel.php 模型,内容如下:
<span class="php"><span class="hljs-meta"><?php
<span class="hljs-class"><span class="hljs-keyword">class <span class="hljs-title">ItemModel <span class="hljs-keyword">extends <span class="hljs-title">Model
{
<span class="hljs-comment">/* 业务逻辑层实现 */
}
</span></span></span></span></span></span></span></span>模型内容为空。因为 Item 模型继承了 Model,所以它拥有 Model 的所有功能。
在 controllers 目录下创建一个 ItemController.php 控制器,内容如下:
<span class="php"><span class="hljs-meta"><?php
<span class="hljs-class"><span class="hljs-keyword">class <span class="hljs-title">ItemController <span class="hljs-keyword">extends <span class="hljs-title">Controller
{
<span class="hljs-comment">// 首页方法,测试框架自定义DB查询
<span class="hljs-keyword">public <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">index<span class="hljs-params">()
{
$items = (<span class="hljs-keyword">new ItemModel)->selectAll();
$this->assign(<span class="hljs-string">'title', <span class="hljs-string">'全部条目');
$this->assign(<span class="hljs-string">'items', $items);
}
<span class="hljs-comment">// 添加记录,测试框架DB记录创建(Create)
<span class="hljs-keyword">public <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">add<span class="hljs-params">()
{
$data[<span class="hljs-string">'item_name'] = $_POST[<span class="hljs-string">'value'];
$count = (<span class="hljs-keyword">new ItemModel)->add($data);
$this->assign(<span class="hljs-string">'title', <span class="hljs-string">'添加成功');
$this->assign(<span class="hljs-string">'count', $count);
}
<span class="hljs-comment">// 查看记录,测试框架DB记录读取(Read)
<span class="hljs-keyword">public <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">view<span class="hljs-params">($id = null)
{
$item = (<span class="hljs-keyword">new ItemModel)->select($id);
$this->assign(<span class="hljs-string">'title', <span class="hljs-string">'正在查看' . $item[<span class="hljs-string">'item_name']);
$this->assign(<span class="hljs-string">'item', $item);
}
<span class="hljs-comment">// 更新记录,测试框架DB记录更新(Update)
<span class="hljs-keyword">public <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">update<span class="hljs-params">()
{
$data = <span class="hljs-keyword">array(<span class="hljs-string">'id' => $_POST[<span class="hljs-string">'id'], <span class="hljs-string">'item_name' => $_POST[<span class="hljs-string">'value']);
$count = (<span class="hljs-keyword">new ItemModel)->update($data[<span class="hljs-string">'id'], $data);
$this->assign(<span class="hljs-string">'title', <span class="hljs-string">'修改成功');
$this->assign(<span class="hljs-string">'count', $count);
}
<span class="hljs-comment">// 删除记录,测试框架DB记录删除(Delete)
<span class="hljs-keyword">public <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">delete<span class="hljs-params">($id = null)
{
$count = (<span class="hljs-keyword">new ItemModel)->delete($id);
$this->assign(<span class="hljs-string">'title', <span class="hljs-string">'删除成功');
$this->assign(<span class="hljs-string">'count', $count);
}
}
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>在 views 目录下新建 header.php 和 footer.php 两个页头页脚模板,内容如下。
header.php,内容:
<span class="hljs-tag"><<span class="hljs-name">html>
<span class="hljs-tag"><<span class="hljs-name">head>
<span class="hljs-tag"><<span class="hljs-name">meta <span class="hljs-attr">http-equiv=<span class="hljs-string">"Content-Type" <span class="hljs-attr">content=<span class="hljs-string">"text/html; charset=utf-8" />
<span class="hljs-tag"><<span class="hljs-name">title><span class="php"><span class="hljs-meta"><?php <span class="hljs-keyword">echo $title <span class="hljs-meta">?><span class="hljs-tag"></<span class="hljs-name">title>
<span class="hljs-tag"><<span class="hljs-name">style><span class="css">
<span class="hljs-selector-class">.item {
<span class="hljs-attribute">width:<span class="hljs-number">400px;
}
<span class="hljs-selector-tag">input {
<span class="hljs-attribute">color:<span class="hljs-number">#222222;
<span class="hljs-attribute">font-family:georgia,times;
<span class="hljs-attribute">font-size:<span class="hljs-number">24px;
<span class="hljs-attribute">font-weight:normal;
<span class="hljs-attribute">line-height:<span class="hljs-number">1.2em;
<span class="hljs-attribute">color:black;
}
<span class="hljs-selector-tag">a {
<span class="hljs-attribute">color:blue;
<span class="hljs-attribute">font-family:georgia,times;
<span class="hljs-attribute">font-size:<span class="hljs-number">20px;
<span class="hljs-attribute">font-weight:normal;
<span class="hljs-attribute">line-height:<span class="hljs-number">1.2em;
<span class="hljs-attribute">text-decoration:none;
}
<span class="hljs-selector-tag">a<span class="hljs-selector-pseudo">:hover {
<span class="hljs-attribute">text-decoration:underline;
}
<span class="hljs-selector-tag">h1 {
<span class="hljs-attribute">color:<span class="hljs-number">#000000;
<span class="hljs-attribute">font-size:<span class="hljs-number">41px;
<span class="hljs-attribute">letter-spacing:-<span class="hljs-number">2px;
<span class="hljs-attribute">line-height:<span class="hljs-number">1em;
<span class="hljs-attribute">font-family:helvetica,arial,sans-serif;
<span class="hljs-attribute">border-bottom:<span class="hljs-number">1px dotted <span class="hljs-number">#cccccc;
}
<span class="hljs-selector-tag">h2 {
<span class="hljs-attribute">color:<span class="hljs-number">#000000;
<span class="hljs-attribute">font-size:<span class="hljs-number">34px;
<span class="hljs-attribute">letter-spacing:-<span class="hljs-number">2px;
<span class="hljs-attribute">line-height:<span class="hljs-number">1em;
<span class="hljs-attribute">font-family:helvetica,arial,sans-serif;
}
<span class="hljs-tag"></<span class="hljs-name">style>
<span class="hljs-tag"></<span class="hljs-name">head>
<span class="hljs-tag"><<span class="hljs-name">body>
<span class="hljs-tag"><<span class="hljs-name">h1><span class="php"><span class="hljs-meta"><?php <span class="hljs-keyword">echo $title <span class="hljs-meta">?><span class="hljs-tag"></<span class="hljs-name">h1>
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>footer.php,内容:
<span class="hljs-section"></body> <span class="hljs-section"></html> </span></span>
然后,在 views/item 创建以下几个视图文件。
index.php,浏览数据库内 item 表的所有记录,内容:
<span class="hljs-tag"><<span class="hljs-name">form <span class="hljs-attr">action=<span class="hljs-string">"<span class="php"><span class="hljs-meta"><?php <span class="hljs-keyword">echo APP_URL <span class="hljs-meta">?>/item/add" <span class="hljs-attr">method=<span class="hljs-string">"post">
<span class="hljs-tag"><<span class="hljs-name">input <span class="hljs-attr">type=<span class="hljs-string">"text" <span class="hljs-attr">value=<span class="hljs-string">"点击添加" <span class="hljs-attr">onclick=<span class="hljs-string">"this.value=''" <span class="hljs-attr">name=<span class="hljs-string">"value">
<span class="hljs-tag"><<span class="hljs-name">input <span class="hljs-attr">type=<span class="hljs-string">"submit" <span class="hljs-attr">value=<span class="hljs-string">"添加">
<span class="hljs-tag"></<span class="hljs-name">form>
<span class="hljs-tag"><<span class="hljs-name">br/><span class="hljs-tag"><<span class="hljs-name">br/>
<span class="php"><span class="hljs-meta"><?php $number = <span class="hljs-number">0<span class="hljs-meta">?>
<span class="php"><span class="hljs-meta"><?php <span class="hljs-keyword">foreach ($items <span class="hljs-keyword">as $item): <span class="hljs-meta">?>
<span class="hljs-tag"><<span class="hljs-name">a <span class="hljs-attr">class=<span class="hljs-string">"big" <span class="hljs-attr">href=<span class="hljs-string">"<span class="php"><span class="hljs-meta"><?php <span class="hljs-keyword">echo APP_URL <span class="hljs-meta">?>/item/view/<span class="php"><span class="hljs-meta"><?php <span class="hljs-keyword">echo $item[<span class="hljs-string">'id'] <span class="hljs-meta">?>" <span class="hljs-attr">title=<span class="hljs-string">"点击修改">
<span class="hljs-tag"><<span class="hljs-name">span <span class="hljs-attr">class=<span class="hljs-string">"item">
<span class="php"><span class="hljs-meta"><?php <span class="hljs-keyword">echo ++$number <span class="hljs-meta">?>
<span class="php"><span class="hljs-meta"><?php <span class="hljs-keyword">echo $item[<span class="hljs-string">'item_name'] <span class="hljs-meta">?>
<span class="hljs-tag"></<span class="hljs-name">span>
<span class="hljs-tag"></<span class="hljs-name">a>
----
<span class="hljs-tag"><<span class="hljs-name">a <span class="hljs-attr">class=<span class="hljs-string">"big" <span class="hljs-attr">href=<span class="hljs-string">"<span class="php"><span class="hljs-meta"><?php <span class="hljs-keyword">echo APP_URL <span class="hljs-meta">?>/item/delete/<span class="php"><span class="hljs-meta"><?php <span class="hljs-keyword">echo $item[<span class="hljs-string">'id']<span class="hljs-meta">?>">删除<span class="hljs-tag"></<span class="hljs-name">a>
<span class="hljs-tag"><<span class="hljs-name">br/>
<span class="php"><span class="hljs-meta"><?php <span class="hljs-keyword">endforeach <span class="hljs-meta">?>
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>add.php,添加记录,内容:
<span class="hljs-tag"><<span class="hljs-name">a <span class="hljs-attr">class=<span class="hljs-string">"big" <span class="hljs-attr">href=<span class="hljs-string">"<span class="php"><span class="hljs-meta"><?php <span class="hljs-keyword">echo APP_URL <span class="hljs-meta">?>/item/index">成功添加<span class="php"><span class="hljs-meta"><?php <span class="hljs-keyword">echo $count <span class="hljs-meta">?>条记录,点击返回<span class="hljs-tag"></<span class="hljs-name">a> </span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
view.php,查看单条记录,内容:
<span class="hljs-tag"><<span class="hljs-name">form <span class="hljs-attr">action=<span class="hljs-string">"<span class="php"><span class="hljs-meta"><?php <span class="hljs-keyword">echo APP_URL <span class="hljs-meta">?>/item/update" <span class="hljs-attr">method=<span class="hljs-string">"post">
<span class="hljs-tag"><<span class="hljs-name">input <span class="hljs-attr">type=<span class="hljs-string">"text" <span class="hljs-attr">name=<span class="hljs-string">"value" <span class="hljs-attr">value=<span class="hljs-string">"<span class="php"><span class="hljs-meta"><?php <span class="hljs-keyword">echo $item[<span class="hljs-string">'item_name'] <span class="hljs-meta">?>">
<span class="hljs-tag"><<span class="hljs-name">input <span class="hljs-attr">type=<span class="hljs-string">"hidden" <span class="hljs-attr">name=<span class="hljs-string">"id" <span class="hljs-attr">value=<span class="hljs-string">"<span class="php"><span class="hljs-meta"><?php <span class="hljs-keyword">echo $item[<span class="hljs-string">'id'] <span class="hljs-meta">?>">
<span class="hljs-tag"><<span class="hljs-name">input <span class="hljs-attr">type=<span class="hljs-string">"submit" <span class="hljs-attr">value=<span class="hljs-string">"修改">
<span class="hljs-tag"></<span class="hljs-name">form>
<span class="hljs-tag"><<span class="hljs-name">a <span class="hljs-attr">class=<span class="hljs-string">"big" <span class="hljs-attr">href=<span class="hljs-string">"<span class="php"><span class="hljs-meta"><?php <span class="hljs-keyword">echo APP_URL <span class="hljs-meta">?>/item/index">返回<span class="hljs-tag"></<span class="hljs-name">a>
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>update.php,更改记录,内容:
<span class="hljs-tag"><<span class="hljs-name">a <span class="hljs-attr">class=<span class="hljs-string">"big" <span class="hljs-attr">href=<span class="hljs-string">"<span class="php"><span class="hljs-meta"><?php <span class="hljs-keyword">echo APP_URL <span class="hljs-meta">?>/item/index">成功修改<span class="php"><span class="hljs-meta"><?php <span class="hljs-keyword">echo $count <span class="hljs-meta">?>项,点击返回<span class="hljs-tag"></<span class="hljs-name">a> </span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
delete.php,删除记录,内容:
<span class="hljs-tag"><<span class="hljs-name">a <span class="hljs-attr">href=<span class="hljs-string">"<span class="php"><span class="hljs-meta"><?php <span class="hljs-keyword">echo APP_URL <span class="hljs-meta">?>/item/index">成功删除<span class="php"><span class="hljs-meta"><?php <span class="hljs-keyword">echo $count <span class="hljs-meta">?>项,点击返回<span class="hljs-tag"></<span class="hljs-name">a> </span></span></span></span></span></span></span></span></span></span></span></span></span></span>
这样,在浏览器中访问 todo 程序:http://localhost/todo/item/index/,就可以看到效果了。

以上代码已经全部发布到 github 上,关键部分加航了注释,仓库地址:https://github.com/yeszao/fastphp,欢迎克隆、提交。
要设计更好的MVC,或使用得更加规范,请看《MVC架构的职责划分原则》。
PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号