一步步编写PHP的Framework(十六)

 

我把模型分成了几块儿,A,B,C,D,E,F,这几块儿分别代表了什么呢?

      首先A,这个Base代表的就是整个框架的基类,所有的模型文件都必须继承自这个基类;

      由于B的内容需要依赖D,所以先说一下D,D首先有一个ConnectionManager,它负责管理数据库的连接和关闭还有数据库驱动的选择,这个命名自己感觉不太好,先就将就吧,既然它负责数据库的连接和关闭,肯定它就有以下方法:

1 <?php
2 public class ConnectionManager {
3    public static function getConnection(){}
4    public static function releaseConnection() {}
5 }

 

     由于数据库的连接对于所有模型来说都是共享的,所以我们把ConnnectionManager设置为单例。

     D中右边有PDO,MYSQL_*,这代表什么意思呢,实际上就是代表各种驱动,有可能你使用的是比较先进的PDO,也有可能你使用的是比较老的MYSQL_*这种,也有可能你使用的是mysqli,ADO等等,正是由于PHP数据库这一块儿的混乱情况,我们需要在框架中定义一个契约,所有的驱动类按照这个契约编写实现,这样,不管驱动类的底层实现怎样,但是上层看到的内容都是一致的。

     现在我们定义一下这个契约:

01 <?php
02 interface IDbDriver {
03     function execute($sql);
04     function connect();
05     function close();
06     function getAllByObject();
07     function getAllByAssocArray();
08     function getAllByArray();
09     function beginTrans();
10     function commit();
11     function rollback();
12 }

 

      connect就是连接数据库,execute就是执行一个SQL,如果这个SQL是一个查询,那么getAllByObject代表将查询的结果通过对象返回,getAllByAssocArray代表将结果按照关联数组返回,getAllByArray代表将结果按照普通数组返回,beginTrans代表开启一个事务,即开启autoCommit,commit就是提交事务,rollback是将事务回滚,close就是关闭Db。

      其实,在将查询的结果返回的时候,还可以封装成为一个iterator。

       好,我们现在再来看看B,首先看看ModelBase,它实际上是提供给表模型和关系模型使用的,它封装了外部可见的各种函数,如query,insert,update,delete,execute,fetchAll等等,那也就是说B中所有的驱动类外部都是不可以直接访问的,那么谁访问呢,就是ModelBase,但是它又不直接访问,而是通过ConnectionManager来访问。

       由于ConnectionManager会按照配置文件自动选择驱动,所以ModelBase也不知道到底它调用的是哪一个驱动类,但是由于驱动类都遵循契约,所以ModelBase不用管到底是那个驱动,就可调用契约上面的方法了。

01 <?php
02 class ModelBase extends Base {
03     protected $_db = null;
04     public function __construct() {
05         $this->_db = ConnectionManager::getConnection();
06     }
07     public function execute($sql) {
08         $this->_db->execute($sql);
09     }
10 }

 

       就比如上面这段代码,首先在实例化ModelBase的时候,就会调用ConnectionManager的getConnection获取数据库的连接,当然,由于ConnectionManager是单例的,所以即使同时实例化了10个ModelBase类,数据库的连接操作也只有一次。

       由于有了上面的契约,在这一层执行一个SQL非常简单,只要调用驱动类的execute方法即可,即$this->_db->execute($sql);

       说了ModelBase,再说一下SQL Parse,它主要的功能就是完成SQL的解析,什么时候需要SQL的解析呢,实现数据库的ORM的时候。

       这一层也是由ModelBase调用的,假设现在外部有一个查询操作,调用的方式是$this->where()->order()->select(),当然,每个函数的参数我都没写,这种函数链非常友好,SQL Parse就会去解析这几个函数的实际意义,然后返回给ModelBase,ModelBase拿到解析之后的SQL,然后执行$this->_db->execute($sql)即可,所以不管花样是那样,最终都还是调用了驱动类的execute方法执行一条SQL的。

       下面的C实际上就容易理解了,就是表模型和关系模型,由于一些操作在ModelBase中已经做完了,所以只要表模型和关系模型继承ModelBase即可。表模型由于处理的是单表的内容,所以它有额外的内容,比如在执行一个$this->select()的时候 ,我们没有指定查询的内容,系统应该能够识别它要查询的表是什么,可能最终解析的SQL就是:select * from XXX了,关系模型也是一样。

        说完了C,E也很容易理解,模型这一层实际上就是调用关系模型或者表模型的方法实现具体的业务即可。

        F中是处理和普通数据库以外的其他内容,比如Cache,由于这里只是讲一下思路,所以这块儿的内容暂时不写,如果有时间就后面再讲,如果没有,那就算了。

时间: 2025-01-26 19:48:49

一步步编写PHP的Framework(十六)的相关文章

一步步编写PHP的Framework(十)

  之前讲了这么多,实际上都只是为框架搭建了一个架子而已,框架里面还没有什么东西, 从今天开始,我就开始从Controller,Model,View这几块儿来分别介绍一下. PS:之前的很多内容我都没有细讲,就比如路由,真正的框架路由肯定不是通过GET方式指定的,而是正则,并且它需要兼容多个Server,多种方式. 我们知道所有的请求都需要经过控制器,所以首先还是说一下控制器. 我们之前已经 说过控制器的概念了,但是这个控制器还是功能太弱了,因为它只是从功能上是控制器,框架并没有为它做任何事情,

一步步编写PHP的Framework(十四)

   今天我说一下怎么在框架中over掉这些安全问题.       首先是SQL注入,这个如果你使用的是PDO,我觉得应该没什么问题,如果你使用的还是mysql_*等API,那么你可以在框架中实现bindParameter或者在插入数据库之前进行字符串转义.       前两天把上一篇文章写完之后,Vian在后面留言说到过SQL注入的一个解决方案,就是在在插入DB之前进行'''.addslashes($id).''',它的意思就是首先进行addslashes操作,之后再强制单引号包裹,这样它就是

一步步编写PHP的Framework(十五)

  从今天开始我们开始介绍模型,模型是一个框架中非常重要的一块儿,控制器实际上不能进行数据的处理,这种处理的过程我们全部放在模型这一块儿来做.         如果是Java,即使是没用框架,它的模型这一块儿也挺复杂的,首先编写service接口,然后写实现,然后定义DAO接口,DAO实现,然后定义这几层之间传输数据的Domain,一般我认为它就是一个POJO.         Java这种契约式的编程方式很不错,即使后面的实现类发生改变,接口没有改变,代码的修改的量也不是很多.        

一步步编写PHP的Framework(十二)

          我上次在讲redirect和forward的时候我就说过,这两个函数要正常使用还需要修改一下Route这个类,至少要将比如域名,控制器名,Action名等存储起来,后面调用redirect,forward的时候可以使用.         现在我们就转到Route.php,原来这个类的代码很简单: 01 <?php 02 class Route extends Base { 03    public static function run() { 04       $contr

一步步编写PHP的Framework(十八)

  上一次我们把模型的驱动类实现了,由于ConnectionManager需要按照配置文件中配置的驱动名实例化驱动类,所以我们先在配置文件中加入驱动名: 01 <?php 02 return array( 03     'defaultController' => 'Index', 04     'defaultAction' => 'index', 05     'debug' => true, 06     'errorReporting' => -1, 07     '

一步步编写PHP的Framework(六)

  不知道大家注意到没有,之前我们导入一个配置文件是通过include CONFIGS_PATH . '/config.php'来做的,这样做好吗?        不忙回答,我可以提两个问题:        1. 如果这个路径下面的config.php不存在会发生什么现象?        2.如果我将PHP这种配置文件修改成为xml这种配置文件之后会发生什么现象?        首先,如果文件不存在,那么PHP会抛出一个警告,但是程序继续执行:配置文件变成xml之后,入口文件处需要编写相应的读取

一步步编写PHP的Framework(十三)

  上次讲到控制器怎么样将数据传递到视图,今天我就主要说一下在程序中怎么让代码更"安全",之后就转到讲模型,再讲怎么做视图,最后再讲控制器的功能强化.       我再声明一下,我写这个文章只是让大家对PHP的框架编写有一个基本的了解,由于本人技术有限,这个文章是给PHP初学者学习的,所以高手勿喷,还有就是我现在时间也有限,所以每次可能需要两三天才能写一篇,每篇我写的时间也要控制在一个小时以内,由于边写这个文章边编代码,所以代码中可能会存在很多BUG,见谅!!        如果你是一

一步步编写PHP的Framework(一)

        框架这个概念可能一开始就吓坏了很多PHP的Coder,其实你只要把一个Framework想明白了,其实也没啥,只是别人功能更复杂,细节考虑的更多,代码质量更高.        框架最重要的一个文件为入口文件,基本上相当于一个总控开关,所有的请求都需要经过这个文件: 1 <?php 2 define('APP_PATH',dirname(__FILE__).'/..'); //应用路径 3 include APP_PATH.'/Library/Toper/Core/FrontCon

一步步编写PHP的Framework(八)

  既然前端控制器控制一切,那么我们可以用它来做更多的事情!! 我们知道,在windows里面默认php.ini中display_errors默认开启,而在linux中默认是关闭的,那么这样对于程序的调试时很麻烦的,所以我们可以在配置文件中设置一个debug属性,它代表是否调试打开,如果打开调试,程序出现任何异常,那么会输出很多调试信息.在这儿,我只是很简单的设置一下,真正的框架调试功能肯定不是这样简单的. 先我们实现如果debug开启,那么显示调试信息debug mode:这样一个字符串,并且