DPT-一种PHP设计模式

上传人:卷*** 文档编号:127878314 上传时间:2022-07-31 格式:DOC 页数:22 大小:44.50KB
返回 下载 相关 举报
DPT-一种PHP设计模式_第1页
第1页 / 共22页
DPT-一种PHP设计模式_第2页
第2页 / 共22页
DPT-一种PHP设计模式_第3页
第3页 / 共22页
点击查看更多>>
资源描述
一、DPT简介PHP为什么在主流的应用中总是那么不杰出,总是不如.Net/Java,就是由于在PHP解决大型应用的时候,那些不完整的面向对象机制、数据库解决的单一,不通用性等等,影响了PHP做大型应用。那么,如何来变化这个状况呢?固然就是需要引进某些新的设计措施,把PHP中不健全的面向对象机制完整起来,进行更好的PHP大中型应用的开发。从Java过来的MVC模式非常流行,并且已有部分已经引伸进了PHP领域,设计模式的引进,就是为了更好的控制项目开发。今天我要说一种设计模式,类似于MVC,它叫DPT模式。其实有时候我也觉得有点象Java里面的DAO(Data Access Object),但是DAO是夹在业务逻辑层和数据库资源层之间的,而DPT更多的是把业务逻辑也封装在类里,和DAO层在相似的内容中。D Data,数据收集层P Php,PHP数据调用层T Template,模板层一方面,我们要对它进行简朴的理解。Data,就是我们的数据层,它不是数据库抽象类,而是通过数据库接口,执行某些SQL,把数据获取的过程,一般把这种操作封装在类里面,就形成了我们的数据收集层。Php,就是对我们收集的数据进行整顿,规划,同步解析模板进行数据的显示。Template,模板层,就是我们的HTML页,里面不涉及任何PHP代码,只有模板标签的内容,通过它来控制数据在页面中有格式的显示。我们这里三层中,每一层都是鼓励由一种人来开发,然后通过PHPDoc之类的工具,把源代码中的API生成文档,由P层的人进行调用。那么,在实际的项目开发中,它是怎么运作的呢,我们又如何把这种设计模式引进我们的项目中呢?我们下面将运用一种实际的项目来解说DPT模式。阅读一下内容必须具有基本的PHP4的面向对象编程、数据库抽象类、模板等知识。我们目前为了加速PHP的开发,都使用PHP封装了部分功能,例如数据库操作抽象类,模板类等等,这些都是为了开发复杂应用而应运而生的。目前比较主流的数据库抽象类有phplib db、PEAR:DB、ADODB等等,模板解决类有phplib template、smartTemplate、Smarty等等。本文中都是使用PHP Group推荐的产品,数据口抽象类使用PEAR:DB,模板解决类使用Smarty,如果对这两个类库不熟悉的读者,请参照文章背面的链接。二、项目体系构造下面我们来构建我们基于DPT模式的PHP应用。(如下部分内容参照MVC模式、类封装还是黑客代码)文献目录构造(只波及到核心的目录)class 类库,涉及所有的数据收集层template 模板文献寄存目录include 常用库,涉及PEAR、Smarty等类库,同步尚有自己定义的基本函数config.inc.php 基本配备文献,涉及数据库配备,其她基本信息配备security.inc.php 安全解决页,重要多传递的变量进行解决init.inc.phperror.php 错误解决页 class目录中寄存了我们数据收集层中的内容,一般的建议是每个类文献只是针对一种表进行操作,例如cmsMessage.class.php,那么这个类就是属于功能CMS里面的,只负责操作Message这个表。所有的数据库交互和操作都是封装在类里的,在P层不容许浮现任何直接操作数据库的语句。template目录中寄存了我们的网页模板,模板中都是使用Smarty标签进行排列的,同步,在模板中,都是建议使用JSCSS来控制页面,模板中只有DIV标签来简朴的排版,这样,非常利于网站改版和更换皮肤。include目录就是对常用文献的涉及,例如PEAR:DB类、Smarty类库文献等。config.inc.php就是基本的配备文献,涉及数据库、基本常量等等,security.inc.php是安全解决页,我们这里重要是做一种变量的安全检查,下面内容我们将仔细简介。init.inc.php是一种初始化操作的页面,涉及初始化数据库链接,实例化模板解决类等等操作,error.php是错误信息解决页,所有的错误信息通过URL编码后转到该页。三、项目基本配备代码核心页代码实例:/* * config.inc.php * 配备文献*/* 数据库配备 */define(DB_HOST, localhost); /数据库主机define(DB_USER, root); /数据库链接顾客define(DB_PASS, ); /连接密码define(DB_NAME, cms); /默认数据库define(DB_PORT, 3306); /数据库端口define(DB_TYPE, mysql); /数据库类型define(DB_OPT, 1); /与否长期链接/* 模板信息配备 */define(TPL_TEMPLATE_DIR, ./template/); /模板目录define(TPL_COMPILE_DIR, ./template/templates_c/); /模板编译目录define(TPL_CONFIGS_DIR, ./template/configs/); /模板配备文献目录define(TPL_CACHE_DIR, ./template/cache/); /模板缓存目录define(TPL_LIFTTIME, 1); /缓存时间define(TPL_CACHEING, true); /与否缓存define(TPL_LEFT_DELIMITER, ); /左边界符define(TPL_RIGHT_DELIMITER, ); /右边界符/* 网站途径配备 */define(ROOT_PATH, dirname(_FILE_); /网站所在根目录define(URL_PATH, dirname($_SERVERPHP_SELF); /网站URL地址途径define(DB_PATH, ROOT_PATH./include/db); /PEAR:DB目录define(TPL_PATH, ROOT_PATH./include/smarty); /Smarty目录/* security.inc.php * 安全过滤文献*/* 过滤规则 */$arr_filtrate = array(, , );/* 过滤函数 */function var_filtrate($var) global $arr_filtrate; foreach ($arr_filtrate as $value) if (eregi($var, $value) return true; return false; /* 获取不同版本下的GET和POST数组 */if (phpversion() 4.1.0) $get = &$HTTP_GET_VARS; $post = &$HTTP_POST_VARS; else $get = &$_GET; $post = &$_POST;/* 检查GET变量 */if (count($get) foreach ($post as $get_var) if (var_filtrate($get_var) exit(Commit get parameter falsity); /* 检查POST变量 */if (count($post) foreach ($post as $post_var) if (var_filtrate($post_var) exit(Commit post parameter falsity); 其实,以上过滤的措施也不是最佳的,建议参照我的另两篇防注入文章获取更好的措施,链接参照附录。/* error.php* 错误解决页面*/if (!isset($getmsg) exit(Not commit parameter);echo Error Message: . $getmsg;echo 返回上一页;就是某些错误解决的作用,一般出的GET方式传递过来的消息都是通过urlencode()过的字符。/* * init.inc.php* 初始化程序*/require_once(dirname(_FILE_).config.inc.php);require_once(ROOT_PATH.security.inc.php);require_once(DB_PATH.DB.php);require_once(TPL_PATH.Smarty.class.php);/* 初始化数据库链接 */$db = DB:connect(DB_TYPE:/DB_USERDB_PASS:DB_HOST/DB_NAME, DB_OPT);if (DB:isErro($db) return $dg-getMessage();$tpl = &new Smarty();/* 初始化模板 */$tpl-templates_dir = TPL_TEMPLATE_DIR;$tpl-compile_dir = TPL_COMPILE_DIR;$tpl-cache_dir = TPL_CACHE_DIR;$tpl-configs = TPL_CONFIGS_DIR;$tpl-lifetime = TPL_LIFTTIME;$tpl-caching = TPL_CACHEING;$tpl-left_delimiter = TPL_LEFT_DELIMITER;$tpl-right_delimiter = TPL_RIGHT_DELIMITER;基本文献描述完毕。代码写了不少,只是为了更好的理解这个模式。四、框架实际开发阐明:我们如下项目代码都是以cms数据库中topic表做例子,代码只是为了演示框架构造,没有对代码进行测试,不保证可以正常运营。topic的表构造:CREATE TABLE topic ( id int(11) NOT NULL auto_increment, title varchar(255) NOT NULL default , addtime int(11) default NULL, author varchar(50) default NULL, type int(11) default NULL, option int(11) default NULL, PRIMARY KEY (id), KEY id (id);(一)Data层:数据采集层Data层重要就是针对数据库的所有操作都封装起来,然后通过接口的形式提供应Php层进行调用,同步在Data层里也封装了某些原始的数据库操作(类似于Java中的DAO)。一般Data层都是类的形式,保存在我们上面的 /class目录下,一般的准则是一种类文献操作一种数据表,就是说不管具体的业务逻辑如何,所有的数据表操作都是封装在一种类文献里的。例如说我们有一种数据表叫做topic,那么我们相应操作的类文献就是:topic.class.php。其实这里是可以做扩展的,例如说,我们的项目非常庞大,有诸多内容,例如涉及有CMS、Blog、BBS等等,那么我们就必须给每一种栏目分派一种数据库,那么针对目前操作数据库的话,就使用类中封装的链接措施进行链接,就可以抛弃我们上面init.inc.php中初始化的操作,而操作在类里面进行的链接。假设我们目前操作的栏目是CMS系统,数据库名叫做cms,那么我们下面构造一种操作cms数据库里面的topic表的类来。/* cms_topic.class.php* 文章解决类*/class cmsTopicvar cmsDBName; /数据库名var cTableName; /目前操作的表名var cDsn; /数据链接源var cDebug; /与否打开调试,1为是,0为否var cDbPointer /链接资源var cfetchMode /获取数据库资料的方式var cEncode /数据库中数据保存的编码格式,默认是UTF-8/* 构造函数 */function cmsTopic() /配备信息从config.inc.php中设立 $this-cfetchMode = DB_FETCHMODE_DEFAULT; $this-cTableName = topic; $this-cDsn = mysql:/. DB_USER.:. DB_PASS. DB_HOST./. DB_NAME; $this-cEncode = utf8;/* 链接数据库 */function connectDatabase() if (!is_object($cDbPointer) $this-cDbPointer = DB:connect($this-cDsn); if ($this-cEncode=utf8) $this-cDbPointer-query(set names utf8); $this-cDbPointer-setFetchMode($this-cfetchMode); if (DB:isError($this-cDbPointer) return false; return $this-cDbPointer; /* 关闭数据库连接 */function closeDatabase() if (is_object($this-cDbPointer) $this-cDbPointer-disconnect(); /*- 数据库基本操作 -*/* 插入操作 */function insert($arr) if(!is_array($arr) | count($arr) = 0) return false; if( = $this-cTableName) return false; $db = $this-connectDatabase(); $res = $db-autoExecute($this-cTableName,$arr,DB_AUTOQUERY_INSERT); if(DB:isError($res) return $res; else $insertId = ($db-getOne(select LAST_INSERT_ID();); if($insertId0) return $insertId; else return true; /* 更新操作 */function update($id,$arr) if( != $id & !(is_array($arr) return false; $db = $this-connectDatabase(); $res = $db-autoExecute($this-cTableName,$arr,DB_AUTOQUERY_UPDATE,id = $id); if(DB:isError($res) return false; else return true; /* 删除操作 */function delete($id) $db = $this-connectDatabase(); $res = $db-query(DELETE FROM .$this-cTableName. WHERE id = $id); if(DB:isError($res) return false; else return true; 上面的代码一种很基本的针对一种表操作的类雏形已经描述出来了,涉及连接数据库,基本的数据库原始操作均有了。你肯定会问,为什么没有把select的操作封装进去?重要是由于select是SQL里最复杂的操作,不也许写那么通用的一种措施去操作它,因此好不如不写,自由发挥。那么我们需要加上某些基本的功能呢?例如读取内容、新增长一篇文章等操作,那么我们还必须在类里面添加某些措施,例如我们增长提取一篇文章内容、提取指定期间的文章、提取指定类别的文章、记录目前所有文章的总数等操作。/* cms_topic.class.php* 文章类增强*/class cmsTopic/ .上面已经描述的措施省略/* * 函数: getTopicContentById() * 功能: 获取指定ID的文章的内容 * 参数: $id 指定要获取的ID * $cols 要提取的字段值 * 返回: 成功返回数据集数组,失败返回错误信息 */function getTopicContentById($id, $cols=*) $db = $this-connectDatabase($this-cDsn); $sql = SELECT $cols FROM . $this-cTableName . WHERE id = $id; $result = $db-getAll($sql); if (DB:isError($result) return $result-getMessage(); else $db-disconnect(); return $result; /* * 函数: getTopicBySpecifyTime() * 功能: 获取指定期间的文章的列表 * 参数: $startTime 指定开始时间 * $endTime 结束时间 * $cols 要提取的字段值 * 返回: 成功返回数据集数组,失败返回错误信息 */function getTopicBySpecifyTime($startTime=0, $endTime=0, $cols=*) $db = $this-connectDatabase($this-cDsn); $start = ($startTime = 0) ? : WHERE addtime $startTime; $end = ($endTime = 0) ? : AND addtime cTableName . .$start . .$end; $result = $db-getAll($sql); if (DB:isError($result) return $result-getMessage(); else $db-disconnect(); return $result; /* * 函数: getTopicByType() * 功能: 获取指定类别的文章的列表 * 参数: $type 指定的类型 * $cols 要提取的字段值 * 返回: 成功返回数据集数组,失败返回错误信息 */function getTopicByType($type, $cols=*) $db = $this-connectDatabase($this-cDsn); $sql = SELECT $cols FROM . $this-cTableName . WHERE type = $type; $result = $db-getAll($sql); if (DB:isError($result) return $result-getMessage(); else $db-disconnect(); return $result; /* * 函数: getTopicSum() * 功能: 获取所有文章总数,如果指定类别,则获取指定类别总数 * 参数: $type 指定的类型 * 返回: 成功返回获取的总数,失败返回错误信息*/function getTopicSum($type=) $db = $this-connectDatabase($this-cDsn); $typeStr = ($type = ) ? : WHERE type = $type; $sql = SELECT count(id) FROM . $this-cTableName . .$typeStr; $result = $db-getOne($sql); if (DB:isError($result) return $result-getMessage(); else $db-disconnect(); return $result; 上面我们构造了某些数据提取类,这应当就是我们Data层的核心了。写措施的时候要尽量考虑到扩展性,例如对列的提取,例如一种措施适合多种状况,例如排序等等,考虑的越多,后来维护起来就比较容易,固然,我推荐的措施是一种措施尽量就做一件事情,如果一种函数要做多种事情,那么就写成多种函数,这样便于代码重用和维护性,我个人觉得一种措施最用不要超过100行。如果函数中有波及到数据库的操作,一定记得结尾的时候把数据关闭掉,否则很容易把服务器资源占用光。固然,你也可以在PHP层去关闭连接。例如,你需要诸多次调用同一种措施,那么这个措施如果反复的连接数据库又关闭数据库,也很挥霍资源,并且速度慢,这个时候就可以把关闭数据库的操作在Php层进行关闭,你可以先构造好一种措施来进行,例如我们上面的 closeDatabase() 措施。(二)Php层:数据调用层PHP层重要就是把从Data层收集的数据再这一层进行调用。由于我们基本的原则就是把所有跟数据库的操作都封装在Data层里,在其她层都不波及到任何的直接对数据库的操作,这样可以进行良好的封装,这样有点类似于 JSP和Javabean,Javabean的类负责和数据库交互,JSP负责调用Javabean来输出数据。我们这里的PHP层就相称于JSP层,前面的Data层就相称于Javabean层,这样玻璃她们之间的耦合度,可以以便程序后来的维护。我们这里的PHP层重要就是复杂从数据库种提取数据,完毕某些简朴的逻辑,然后把数据输出到Template(模板层)。目前我们运用示例代码来看看PHP层是如何调用Data层的数据的。/* topic_list.php* 文章列表程序*/* 涉及基本文献 */require_once(init.inc.php);require_once(class/cms_topic.class.php);/实例化Data层对象$topic = new cmsTopic();/获取文章类型变量$topicType = intval(get(type);/从Data层中把数据提取过来$topicList = getTopicByType($topicType);/给模板变量赋值后输出页$tpl-assign(topic, $topicList);$tpl-assign(topic.html);代码是不是很简朴?就是把数据获取过来,然后解析到模板层中去解决,因此这样如果后来浮现问题改起来比较容易,例如是数据获取的问题,那么直接改上面的类文献就行,如果是模板显示的问题,那么直接修改模板层中的相应的模板页就可以,非常便于维护。(三)Template层:模板层这个模板层就是我们常说的网页了,但是这里就是涉及了某些Smarty的模板变量和HTML混和,模板页解决的时候就对页面中的模板变量进行替代,最后我们看到的成果就是模板页和PHP层中的程序输出混和的成果。一般模板页设计的时候,最佳遵循Web原则,就是说尽量在页面中不使用表格等html标签来控制页面,而是使用div层来寄存数据,使用css样式表来控制页面布局,这样对涉及JavaScript脚本的编写,后来页面的改版等等非常有好处。并且如果要还模板也很简朴,只需要把css文献替代就可以达到效果。固然,如果对web原则不理解,那么建议去阅读一下网站重构这本书。我们下面就简朴的描述一下Template(模板层)的代码是如何的。* 加载头部文献 *include file=header.html* 模板主体 * 左边导航条 *文章列表section name=topicList loop=$topic 标题:$topictopicList.title|escape:html|truncate:30:.:true | 时间:$topictopicList.addtime|date_format:%Y年%m月%d日 | 作者:$topictopicList.author|escape:htmlsectionelse 临时没有任何文章/section* 加载底部文献 *include file=foot.html模板页中大体也许有某些JavaScript程序,或者有样式文献,一般使用样式文献来控制页面的布局和显示效果。我们这里没有具体的描述,在实际项目中可以由网页制作人员去负责。五、使用DPT模式的项目规划一般在所有的软件项目或者是网站项目中,要保证一种项目可以顺利完整的完毕,那么便需要技术主管或者架构师良好的设计和管理。一般所有项目中人是最难控制的因素,你可以把项目指定的非常完善,架构可以选择的非常合理,但是你不能控制人的因素,不能保证项目的中的某个成员也许在任何时候离开项目。当在PHP项目中,如果一种项目角色忽然的拜别,也许导致项目要停止,要重新找人来接替,影响了项目的进度,那么如何有效的控制和解决这些问题。在一种使用DPT设计模式的项目中,项目中个个角色分别有网页设计师、网页制作人员、客户端脚本JavaScript程序员、服务器端PHP程序员。她们的分工都是什么呢?网页设计师负责设计网页的界面,生成效果图,然后由网页制作人员去做成网页,固然,如果是遵循Web原则的项目的话,那么网页制作人员重要的任务就是负责页面布局样式的编写。客户端程序员重要是负责客户端脚本的编写,例如针对页面中需要使用的JavaScript进行编写,PHP程序员重要是负责我们上面Data & PHP & Template 三层的代码编写,固然,如果项目足够庞大,完全可以拆分出来,有PHP程序员负责Data层,有PHP程序员负责Php和Template层,分工清晰,Php层程序员只是需要调用Data层程序员已经写好的类库进行调用,不用关怀类是如何实现的。这样一种项目架构下来,可以按照任务需要来安排某个模块的人的数量,最大限度的把项目规划好。固然,项目中某些必要的因素是要考虑的,例如,如何让网页制作人员、客户端脚本程序员和PHP程序员良好的合伙,那么就是分离她们的责任,例如,模板页必须由PHP程序员来编写,然后提交给JavaScript程序员制作客户端脚本,最后再由网页制作人员通过CSS来控制布局,那么Php程序员在模板页中就必须使用div等标签来定义一种块的数据,如果任何一块出了问题,那么相应找相应负责人,就可以较好的避免彼此推卸责任,或者权责不分的状况,这样有助于管理,也有助于每个开发成员之间的良好合伙。为了避免项目失控,或者不会由于项目成员的离开而影响项目的进度和管理,必须有相应的措施和规则。我们重要针对PHP程序员来进行描述,部分措施同样合用于网页制作人员和客户端脚本程序员。(1)编码规范项目开发中为了便于维护和后来其她人接手代码,必须统一编码规范,涉及对目录、文献名、类、函数、变量、注释等等都必须遵循原则,并且为了代码的维护,必须规定PHP程序员编写注释。目前基本遵循的是Fredrik Kristiansen写的PHP 编码规范,或者是PEAR中代码的规范。如果代码为了做成接口,或者需要做成参照的文档以便后来维护代码,使用phpDoc等工具,那么为了可以使用PEAR包中的phpDoc可以正常辨认,因此一般建议遵循PEAR包的规范,重要是DPT模式中Data层中类的的编码必须规范。PEAR中pear.php中基类的部分代码:class PEAR /* 属性的描述 */ / properties /* * Whether to enable internal debug messages. * * var bool * access private */ var $_debug = false; /其她属性省略. / /* 对措施的描述 */ / constructor /* * Constructor. Registers this object in * $_PEAR_destructor_object_list for destructor emulation if a * destructor object exists. * * param string $error_class (optional) which class to use for * error objects, defaults to PEAR_Error. * access public * return void */ function PEAR($error_class = null) /措施内部代码省略. / 对于上面内部标签的解释请参照文章结尾链接中的php Documentor 1.2.2 使用阐明规范(2)单元测试单元测试是对程序进行的第一步测试,并且是程序员自己做的测试,没有谁比自己更理解自己写的代码,因此单元测试对保证程序的稳定性尤为重要。因此一般项目中,特别是写类库的程序员,一定要对自己写的代码进行单元测试,只要保证数据可以稳定的获取,才干保证Php层的程序员可以对的的获取数据。针对PHP的单元测试工具目前有SimpleTest和PEAR包中的phpUnit/phpUnit2,phpUnit2是针对PHP 5的测试工具,这个可以按照项目的实际状况来决定使用什么测试工具。SimpleTest和phpUnit的使用参照文章请参照文章最后的链接。(3)程序安全在今天这个黑客横行,SQL Injection泛滥的时候,为了保证程序可以对的完整的运营,那么就必须规定程序员对自己的程序进行安全的编码。重要是两方面,一方面是服务器端的安全,重要就是要过滤顾客提交的变量,记得网络上流行的一句话:“不要相信顾客提交的任何数据”,由于你不能保证这个顾客是歹意的还是善意,是一般顾客还是黑客,因此不管是谁,一定要过滤掉它的变量,但是是通过GET方式还是POST方式过来的数据,统统过滤。重要是过滤某些特殊自如,例如/等等,保证服务器和数据的安全。另一方面就是针对客户端的威胁,例如提交某些歹意的JavaScript代码,当一般顾客查看该页的时候,那么将给对方带来影响或者伤害,那么会极大的影响网站或者软件的名誉,这是要避免的。同样的,这个也是要良好的过滤变量,如果无法在顾客提交数据的时候过滤,那么就在显示输出的时候进行过滤,重要是过滤某些HTML标签和JavaScript代码,保证客户浏览的安全。(4)代码同步(版本管理)但一种项目是多人开发的时候,那么代码同步或者说是版本管理就尤为重要,由于为了保证每个开发成员的代码都是最新的,最稳定的,那么必须要使用CVS等版本管理工具,固然,你想使用VSS也无可厚非。一般建议是专门使用一台服务器来供所有开发人员开发,不建议把代码保存在开发人员的本地上,由于大部分人都是使用Windows等操作系统,如果发生病毒感染、设备损坏或者其她因素,那么代码将壮烈牺牲,这样导致又要反复开发的挥霍,如果把代码直接寄存在服务器上,一般服务器安装都是Unix/Linux系统,可以基本保证代码的安全和完整。 (5)多模块通信如果项目足够庞大,门户级的应用,那么肯定波及到多栏目/模块之间的通信六、结束语DPT模式也许在诸多项目中你已经应用了,只是没有认证的进行定义,如果阅读本文可以获得同感,或者恍然大悟乃至垂手顿足,那么我想本文就给了你一定协助,这就足够了。写作文章前前后后花了快一种月,只是始终太懒惰,怕的写的不好,怕这个东西出来没故意义。但是不管如何,还是写出来了。如果也许,尝试考虑把你的PHP应用移植到PHP5上,也许,那才是你需要的。
展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 办公文档 > 解决方案


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!