设计模式MVC(PHP实现二)

Posted 星点学习

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式MVC(PHP实现二)相关的知识,希望对你有一定的参考价值。

上一篇文章发完之后我总感觉写MVC不是很好,设计模式的确没有那么花俏,中间还有一些细节比较晦涩难懂,当然,也可能是我描述不到位

但是,既然写了,那么应该善始善终把它写完

这次继续上次的文章  

上次我们已经初步把控制层Controller(后面简称C层),跟View视图层(后面简称V层)初步完整并整合一起,当然,我们并不是真正做一个框架

而是学习一下模型视图控制器三层模式

所以,除了基本的功能之外,其他都不会具体实现,有兴趣的朋友可以去尝试一下

model 模型层

模型层对象通常负责在数据库中存储数据

那么,让我们先来连接数据库把

还记得上一次我们已经把数据库的连接参数准备好了吗

$config = array('host'=> 'localhost',
                       'type' => 'mysql',
                       'user' => 'root',
                       'password' => '',
                       'name' => 'test',
                       );

我们把上次这个东西放在了Core核心类的start方法中,这样做显然是不合理

当我们的项目越做越大时,一定会有更多一些其他的参数需要维护,其中一些参数有些可能还会经常变动

这样我们可能就必须经常修改代码,而且配置参数放置在代码中也是不容易被理解

想一想吧,当你接手一个项目时,发现里面全是杂乱无章的代码,配置参数跟逻辑代码混合在一起

添加一个小功能或修改一个小BUG竟然需要阅读上千或更多代码,那会是怎么的心情呢

最好避免这样的事情就是先自己做好

所以,我们将配置参数分离出来,保存在一个配置文件中

我们在主目录下新建一个config文件夹,再在里面新建一个文件config.php

$config = array(
   'host'=> 'localhost',  //数据库主机

   'type' => 'mysql',      //数据库类型

   'user' => 'root',       //数据库用户

   'password' => '',       //数据库密码

   'name' => 'test',       //数据库名称
);
return $config;

当然,这里最好加上注释是最好的

然后我们可用

$config = require(APP_PATH . 'config/config.php');

来获取配置参数,其他不变

这样做之后,代码看起好了一点

但是想到我们开发的时候,也需要用到一些配置参数

所以,我们应该把配置设为全局变量

当然,直接操作全局变量不安全也不合理

所以,我们还需要一个函数来获取这些配置参数

那么我就需要用到自定义的函数了

我们在includes目录下,新建一个functions.php来存放我的自定义函数

/*获取参数配置
*name  配置名
*return  配置值
*/

function  get_config($name='') {
   global $config;
   if(empty($config)) return null;
   if(!empty($name)) {
        return $config[$name];
   } else {
       return $config;
   }
}

这样,通过get_congif()函数我们就获取配置参数了

当然

global $config;

$config = require(APP_PATH . 'config/config.php');

同样把config设为了全局变量

最最重要的是

我们需要在index.php 中加入一句

require(APP_PATH . 'includes/functions.php');//引入自定义函数

然后我们才可以调用我们的函数

ok,简单测试一下,我们在indexController下试试输出配置参数

public function index(){
   print_r(get_config());
}

可以获得了全部全部参数

这里的顺序我安排错了,本来我们应该先简单连接数据库,然后再将参数提取出来

最后才是分离出来成为配置文件,这样才符合一般的开发规律

不过问题不大,我们将错就错,继续来完成

连接数据库

这里我使用的mysql,连接的方式有三种,分别是

1.mysql
2.mssqli
3.PDO

第一种是比较古老的面向过程的连接方式,不安全,不是很建议使用

第二种是第一种的增强扩展,也是面向对象的连接,建议使用

第三种是php中的一个数据库抽象层规范,提供一个统一的接口,类似于JDBC,ODBC

PHP 数据对象 (PDO) 扩展为PHP访问数据库定义了一个轻量级的一致接口。实现 PDO 接口的每个数据库驱动可以公开具体数据库的特性作为标准扩展功能。 注意利用 PDO 扩展自身并不能实现任何数据库功能;必须使用一个 具体数据库的 PDO 驱动 来访问数据库服务。

上面引用的官方的简介加以说明

这里我选择了第三种,第二种虽然功能强大,安全性高,支持的特性多,但是缺乏灵活性,不能支持其他的DBS(数据库系统,下同)

为了使框架的受众更多,我们应该尽量考虑更多灵活性的处理,开发软件或其他开发也同样适用

现在我先初步尝试连接

在Model类中添加一个静态方法connect用来连接

public static function connect($config) {
   try {
       $dsn = sprintf("mysql:host=%s;dbname=%s;charset=utf8", $config['localhost'], $config['name']);

       self:: $_dbHandle = new PDO($dsn, $config['user'], $config['password']);
       //测试
       //foreach(self:: $_dbHandle->query('SELECT * from student limit 1') as $row) {
        //   var_dump($row);
       //}
   } catch (PDOException $e) {
       print "Error!: " . $e->getMessage() . "<br/>";
       die();
   }
}

通过PDO的架构函数创建了一个数据库连接实例,并保存在Model的一个静态变量$_dbHandle中

函数原型

PDO::__construct ( string username [, string driver_options ]]] )

第一个参数为连接数据的信息

数据源名称或叫做 DSN,包含了请求连接到数据库的信息

通常,一个 DSN 由 PDO 驱动名、紧随其后的冒号、以及具体 PDO 驱动的连接语法组成

第二个参数为DSN字符串中的用户名

第三个参数为DSN字符串中的密码

第四个参数为一个具体驱动的连接选项的键=>值数组

为了让connect方法可以连接更多的DBS,我们可以把第一个参数抽象出来

编写其他DBS的对应连接信息,利用配置参数的type,根据不用的DBS,选择不同的连接信息

因为我并没有安装其他的DBS,不方便测试,所以这里不提供代码,有兴趣的朋友可以尝试一下

$conf = get_config()
Model::connect($conf);

简单测试一下

设计模式MVC(PHP实现二)

没有报错,并出现了数据,说明我们已经连接成功了

我们接着完善一下

public function query($sql) {
   $sth = self::$_dbHandle->query($sql);

   return $sth->rowCount();
}

添加一个query方法,传入sql语句,返回影响条数

$db =new Model();
$rowCount = $db->query("delete from student where sno = 6");

运行一下,发现没有什么问题

但有时候我们需要查询,并且返回的是一个结果集

public function select($sql) {

   $sth = self::$_dbHandle->query($sql);

   return $sth->fetchAll();

}

一样,测试一下

$db =new Model();
$list = $db->select("select * from student");

发现,没什么问题

设计模式MVC(PHP实现二)

虽然向select这样的函数可以满足一般的查询

但是如果查询条件比较复杂,那么这样写sql语句毫无疑问效率极低

我们尝试来改写select方法,并将查询写成连贯操作(时间原因,仅完成一小部分功能)

protected $_table;
protected $_where = '';
protected $_order = '';
public function where($where) {
   $whereStr = '';
   if(is_string($where)){
       $whereStr = $where;
   }else{
       if(isset($where['_logic'])) {
           //逻辑操作 OR AND XOR 默认是 AND
           $operate  = isset($where['_logic'])?strtoupper($where['_logic']):'';
           $operate    =   ' '.$operate.' ';
           unset($where['_logic']);
       } else {
           $operate = ' AND ';
       }
       foreach($where as $key => $value) {
           if($key == '_logic') continue;
           else {
               if(is_array($value)) {
                   $_str = '';
                   foreach ($value as $value) {
                       $_str .=  sprintf("%s = %s", $key,$value);
                       $_str .= ' OR ';
                   }
                   $_str = substr($_str,0,-4);
                   $whereStr .=  sprintf(' ( %s ) ', $_str);
               } else {
                   $whereStr .=  sprintf("%s = %s", $key,$value);
               }
           }
           $whereStr.=$operate;
       }
       $whereStr = substr($whereStr,0,-strlen($operate));
   }
   // echo $whereStr;
   if(!empty($whereStr)) {
       $this->_where = ' WHERE '.$whereStr;
   }
   return $this;
}
public function order($order=null) {
   if(!empty($order)) {
       $this->_order = ' ORDER BY '.$order;
   }
   return $this;
}

where方法可以接受字符串参数,也可以接受数组参数,再解析成sql语句

order方式接受一个字符串参数,表示按某个字符升序或降序排列

$student =new Model('student');
$where['sno'] = array('1', '2');

$list = $student->where($where)->order('sno DESC')->select();

上面实例化一个Model对象,并通过连贯操作,查询了学号为1和2的用户的信息,并按学号降序排列

这样写起来就轻松许多了,而且也比较友好,由于时间原因,这里这是简单的写了两个函数,其他的不在这里实现

总结

学到这里,我们已经大概知道MVC是个什么东西了

MVC将数据模型、逻辑操作、用户视图分离开来

降低开发中的耦合,使代码更加清晰,方便后期的维护

当然,这可能会损失一部分性能为代价,也需要我们去遵守一些开发规则

但是,比起团队开发的好处,这些缺点都是可以容忍的

虽然说MVC是设计模式,但是我觉得比起其他设计模式,比如单例,适配器,MVC更像一种架构

有许多出名的框架的以MVC三层模式为核心架构,虽然,我也只懂得很小的一部分,修行之路慢慢而远兮

还需要学更多的知识才能够深刻理解前人的用意

本人水平有限,上面文章难免有疏漏,如果你愿意指出来,不胜感激


以上是关于设计模式MVC(PHP实现二)的主要内容,如果未能解决你的问题,请参考以下文章

PHP 框架实现原理

php之mvc(简单实现)

如何实现MVC模式

04mvc框架原理(8days)02

VSCODE 片段 PHP 自动填充命名空间

html PHP代码片段: - AJAX基本示例:此代码演示了使用PHP和JavaScript实现的基本AJAX功能。