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

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

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

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 Security, Privacy and Commerce, 2nd Edition

Web Security, Privacy and Commerce, 2nd Edition

Simson Garfinkel / O'Reilly Media / 2002-01-15 / USD 44.95

Since the first edition of this classic reference was published, World Wide Web use has exploded and e-commerce has become a daily part of business and personal life. As Web use has grown, so have ......一起来看看 《Web Security, Privacy and Commerce, 2nd Edition》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

随机密码生成器
随机密码生成器

多种字符组合密码

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具