自定义MVC框架 -封装控制器层

栏目: 数据库 · 发布时间: 6年前

内容简介:控制器的作用是作为模型于视图之间的桥梁,细分的话有两个创建模型类时时按照表划分的,也就是说一张表对应一个模型类创建控制器则应该按照功能划分,如以前编写的博客系统,后台有模块“博客管理”、“类别管理”、“评论 管理”,我们则应该每个模块对应一个控制器

1. 概念

控制器的作用是作为模型于视图之间的桥梁,细分的话有两个

  • 获取视图提交的数据,转发给模型
  • 获取模型的数据,转发给视图

创建模型类时时按照表划分的,也就是说一张表对应一个模型类

创建控制器则应该按照功能划分,如以前编写的博客系统,后台有模块“博客管理”、“类别管理”、“评论 管理”,我们则应该每个模块对应一个控制器

2. 创建控制器

控制器类应该创建在controller 目录下,每个类就是一个控制器,我们称为控制器类

控制器文件的命名规范

1)功能名称+Controller.class.php

2)控制器名称也采用大驼峰写法,如UserController、NewsTypeController

3)控制器中的方法使用小驼峰写法,如 selectAction、getInsertIdAction

4)如上,方法名称后面加上Action后缀

2.1 创建UserController

创建一个控制器,用于管理所有的用户数据

在controller下创建UserController.class.php 文件

自定义MVC框架 -封装控制器层

在控制器中编写方法,用于向users表中添加数据

<?php

class UsersController
{
    public function addAction()
    {
        require_once 'model/Factory.class.php';
        $model = Factory::M("UsersModel");
        $model->users_add();
    }
}

我们发现,控制器中的addAction 方法调用了模型类中的users_add方法

这就是我们前面所说的:模型类负责与数据库交互,控制器负责调用模型类

为了更加清晰的理解控制器与模型的关系,在控制器中再编写一个用于查询的方法

public function selectAction()
    {
        require_once 'model/Factory.class.php';
        $model = Factory::M("UsersModel");
        $users = $model->users_select();
        var_dump($users);
    }

控制器中的selectAction 方法调用了模型中的方法获取数据库中的数据,这也是控制器调用模型类获取数据的经典案例

为了查看效果,我们运行当前的程序,调用控制器的方法,看看结果

问题来了?我们在浏览器中怎么输入地址呢?直接访问控制器类?绝对不行的。

解决方案是,在网站根目录下创建一个 php 文件,可以命名为 index.php

我们在浏览器中访问这个文件,然后在这个文件中,实例化控制器类,再调用控制器中的方法

require_once 'controller/UsersController.class.php';
$controller = new UsersController();
$controller->addAction();

查看数据库,一条记录被保存到数据库中、

修改代码,改为调用select方法查询数据库的数据

require_once 'controller/UsersController.class.php';
$controller = new UsersController();
$controller->selectAction();

2.2 路径问题

先不忙着仿照UsersController类创建另外的两个控制器

2.2.1 当前的问题

上面代码中,我们在控制器中引入了模型中的Factory.class.php文件

require_once 'model/Factory.class.php';

但是观察一下当前的目录结构

自定义MVC框架 -封装控制器层

发现,UsersController和Factory.class.php 分布在两个目录下,所以按照正常的写法应该是

require_once '../model/Factory.class.php';

但这种写法是无法被正确加载的

原因在于,index.php 是我们在浏览器中访问的文件,在这个文件中引入了 UsersController.class.php

require_once 'controller/UsersController.class.php';

我们讲过,所谓引入和包含,其实就是将这个文件中的代码全部拷贝一份到当前文件中,也就是拷贝到了index.php 中,所以,UsersController中引入其他文件时,应该时站在index.php的角度,所以使用下面的方式引入

require_once 'model/Factory.class.php';

其实,我们发现,这种方式进行文件引入和包含,路径很容易写错,而且我们当前还有一个隐藏的问题,就是Factory类中的如下代码

自定义MVC框架 -封装控制器层

因为Factory.class.php文件在model目录下,所以这里的引用都是相对于model目录的

这在我们工厂类创建魔形类的对象时没有问题

$model = Factory::M("UsersModel");

但使用工厂类创建控制器类,就会出错,修改index.php 代码

自定义MVC框架 -封装控制器层

运行就会出现错误

自定义MVC框架 -封装控制器层

总结一句话,我们当前引入文件的方式是有问题的,有没有一种稳妥的方式呢?

2.2.2 解决方法

绝对路径+自动加载

首先换成绝对路径

绝对路径就是带盘符的路径

具体方法是在index.php文件中,声明常量用来存储index.php文件的目录,也就是当前网站的根目录

define("APP_PATH",__DIR__."/");
echo APP_PATH;

输出结果为:

D:\phpStudy\PHPTutorial\WWW\testMVC/

然后在所有文件中,凡是引入文件的地方,全部都使用绝对路径的方式拼接,这样就不用考虑当前文件和被引用文件的位置关系了

如UserController中

require_once APP_PATH.'model/Factory.class.php';

引入时只需要知道 model目录与 网站根目录的关系即可,不需要再考虑UsersController.class.php与UsersModel.class.php的关系了

但是这仍然没有解决使用工厂类无法创建控制器对象的问题

当然可以使用判断的方式解决

将Factory类的M方法更改如下,在包含文件前,先根据关键词进行判断

public static function M($classname)
    {
        static $model_list = [];
        if (!isset($model_list[$classname])) {
           if (strpos($classname,"Controller")){
               require_once APP_PATH."controller/".$classname.".class.php";
           }else{
               require_once APP_PATH."model/".$classname.".class.php";
           }
            $model_list[$classname] = new $classname();
        }
        return $model_list[$classname];
    }

然后index.php中修改代码如下,使用工厂类创建类的对象

define("APP_PATH",__DIR__."/");
require_once APP_PATH.'model/Factory.class.php';
$controller = Factory::M("UsersController");
$controller->selectAction();

现在使用自动加载解决遍布各处的文件引入代码

修改index.php

define("APP_PATH",__DIR__."/");
/*require_once APP_PATH.'model/Factory.class.php';*/
function load1($classname){
    $file=APP_PATH."controller/".$classname.".class.php";
    if (file_exists($file)){
        require_once $file;
    }
}
function load2($classname){
    $file=APP_PATH."model/".$classname.".class.php";
    if (file_exists($file)){
        require_once $file;
    }
}
spl_autoload_register("load1");
spl_autoload_register("load2");

$controller = Factory::M("UsersController");
$controller->selectAction();

然后删除各个文件中的文件引入代码,包含Factory中的M类

public static function M($classname)
    {
        static $model_list = [];
        if (!isset($model_list[$classname])) {
            $model_list[$classname] = new $classname();
        }
        return $model_list[$classname];
    }

但是Model.class.php 中的引入保留,或者再加入一个自动加载类函数

测试程序能够正常运行

2.3  编写其他控制器类

仿照UsersController 类编写另外两个类的代码


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Web应用测试

Web应用测试

纽恩 (Hung Q.Nguyen) / 冯学民 / 第1版 (2003年4月1日) / 2003-4 / 29.0

一起来看看 《Web应用测试》 这本书的介绍吧!

URL 编码/解码
URL 编码/解码

URL 编码/解码

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具