热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

ThinkPHP框架设计及扩展详解_php实例

ThinkPHP框架是国内知名度很高应用很广泛的php框架,我们从一些简单的开发示例中来深入了解一下这个框架给我们带来的开发便捷性,以及游刃有余的扩展设计。同时也从源码分析的角度看

ThinkPHP框架是国内知名度很高应用很广泛的php框架,我们从一些简单的开发示例中来深入了解一下这个框架给我们带来的开发便捷性,以及游刃有余的扩展设计。同时也从源码分析的角度看看框架的一些不足,尽量做全面客观的评价。这里假设大家已经使用过ThinkPHP框架,基本使用方法请参考官方文档。

一、框架分层及url路由

框架的安装非常简单,下载后放入web服务器的目录即可,但是建议大家不要用默认的入口文件位置,而是放入单独的目录,便于保护代码和数据。例如我的入口文件和web服务器配置目录在web目录(外层框架里的index.php没有删除但是没有使用):

同大多数MVC框架一样,我们只需要按框架的目录结构,扩展自己的Controller和View,一些页面就开发完成了。ThinkPHP提供Module、Controller、Action三层结构来组织自己的url(3.1版本叫分组、Action和method,3.2更加国际范),目录结构如下:

这里强烈建议大家:
1、业务单独分层,不用放在Controller和Model里,例如我这里通过扩展函数库Application/Common/Common/function.php强制定义业务层名称为Service:

function service($name)
{
return D($name, 'Service');
}

好处是复用性好,假如将来要开发wap页面,写了不同的Controller,就可以复用service,假如以后的数据存储变了,比如把数据库从mysql迁移到mongodb之类,那修改Model就可以,service还是不需要任何修改。

2、基础模块和业务模块分开,不要相互引用。基础模块(例如用户基本信息)只提供数据接口没有Controller和View。
三层目录已经可以应对一般的web应用,更加复杂的web应用我们可以定义不同的入口文件加载不同的Application来解决。更更复杂的应用?门户和超大规模网站么,那就不是一个php框架能解决所有问题的了,需要自己的中间件和定制框架。

ThinkPHP的支持4种url访问模式,分别是:

1、普通模式,传统url模式,所有参数分开,例如
http://localhost/tp/index.php?m=Ucai&c=User&a=index¶=xxx
路由参数:m参数表示模块,c表示控制器,a表示访问方法
2、兼容模式
http://localhost/tp/index.php?s=/Ucai/User/index/para/xxx
路由参数通过s参数组装,当然数据参数也可以不必放在s参数里
3、pathinfo模式
http://localhost/tp/index.php/Ucai/User/index/para/xxx
这种模式把入口文件和真实脚本放在一起,含义明确,也便于SEO
4、rewrite模式
http://localhost/tp/Ucai/User/index/para/xxx
这种模式通过web服务器的rewrite配置隐藏入口文件,显得更加友好
其中pathinfo和rewrite模式需要web服务器支持。ThinkPHP有个配置需要设置为哪种模式,其实是用在U方法里生成url链接的时候用到的,访问的时候只要web服务器支持用哪种方式都可以。
也建议ThinkPHP其实不需要配置,而是记住用户访问的方式,只要第一个访问用的是哪种模式,以后生成的url都用这种方式生成,因为用户都已经访问到了就不存在支不支持的问题了。

如果正常的url不能达到我们的要求,还可以通过配置路由进一步优化url,例如我们想把url配置的更加简单
http://localhost/tp/Ucai/login/xxx
我们只需要在模块配置文件中添加如下的路由配置即可,如果用正则表达式则可以更加简化

'URL_ROUTE_RULES'   =>  array(
'login/:para' => 'Ucai/User/index',
'login' => 'Ucai/User/index',
),

到这里我们可以看到,ThinkPHP框架支持的层次结构和url配置非常丰富,能满足各种不同的需求。当然我们建议大家不要滥用路由配置,适当少量的配置能带来更好的seo效果,但是大量的配置会给项目的维护和修改带来困难。

二、ThinkPHP扩展

ThinkPHP本身含有丰富的组件和驱动,我们以数据库驱动扩展和行为扩展为例来了解一下ThinkPHP的扩展设计。

三、数据库驱动扩展

虽然ThinkPHP提供了众多的数据库驱动,但是也并不能满足所有的需求。例如我们的数据很可能不是通过直接访问数据库去实现,而是通过一些中间件(例如C程序)进行转发,从而获得更好的性能,这时就需要扩展数据库驱动来支持。
扩展非常简单,在DB/Driver目录下新建自己的驱动,例如Custom.php,然后实现request和execute方法扩展就算完成了,然后再配置文件里配置DB_TYPE=’custom’,就可以使用了。这里的request表示查询,execute表示更改数据,所有其他操作都会在Model里进行解析,包装成sql语句调用这两个方法执行。
例如我所实现的最简单的query方式,通过shell命令调用sqlite执行sql语句:

public function query($str) {
$cmd = sprintf('sqlite3 %s "%s"', $this->config['params']['dbfile'本文来源gao@daima#com搞(%代@#码@网&搞gaodaima代码], $str);
exec($cmd, $arr);
}

当然这个只是示例,ThinkPHP本身就支持sqlite3,通过pdo的方式去连接就可以。实际的应用环境可能是通过连接4层协议访问中间层端口获取数据。

四、Behavior行为扩展

Behavior行为设计是ThinkPHP框架的核心,通过行为配置和扩展,为系统的伸缩性和定制性提供了最大的支持。
假如我们要加入登录验证的功能,按照常规我们会设计自己的父类Controller,然后所有其他的Controller都从这里继承。但有了Behavior会变得更加简单和灵活,我们只需要在tags.php(没有的话在配置目录新建)添加一个Behavior就可以了:

return array(
'action_begin' => array('Ucai\Behavior\AuthBehavior'),
'view_begin' => array('Ucai\Behavior\OutputBehavior'),
);

程序在执行到action_begin流程时就会调用这个Behavior,我们可以根据状态进行跳转或终止执行。

namespace Ucai\Behavior;
class AuthBehavior {
// 行为扩展的执行入口必须是run
public function run(&$return) {
//不需要验证的action设置为true
if (!$return['AUTH_PUBLIC']) {
if (service('User')->checkLogin())
{
$return = true;
}
else
{
header('Content-Type: text/html; charset=utf-8');
redirect(U('User/index', array('url' => $_SERVER['HTTP_REFERER'])), 5, '需要登录,5秒后跳转。。。');
}
}
}
}

对于不需要登录的页面我们可以在Controller里添加配置,所有不配置的都会要求登录验证。

public $cOnfig= array('AUTH_PUBLIC' => true);

这里大家对继承和Behavior实现登录验证做一个对比,可能觉得区别不大。但是在一个复杂的项目里,这种功能会非常多,如果每个功能都放到父类里,就会非常庞大,并且部分子类可能又不需要,这时候用Behavior去定制流程就会显得游刃有余。
在上面的配置中我们还发现了一个配置OutputBehavior更能说明问题,大家有没有猜到,这个Behavior我是用来在view里输出一些共有变量,例如jscss的域名和路径等。在没有Behavior之前,大家是不是需要一个公共方法,然后每个页面都去调用一次,或者改写View的类代码?有了Behavior就显得方便许多。

namespace Ucai\Behavior;
class OutputBehavior {
public function run(&$return) {
$view = \Think\Think::instance('Think\View');
$view->assign('STATIC_URL', 'http://p3.ucai.cn/static');
}
}

扩展总结:通过Behavior扩展和数据库驱动扩展大家可以看到,ThinkPHP提供了很灵活的扩展和增强机制,能满足众多需求。其他存储、缓存、日志、模板引擎等如果需要也能很方便的扩展。

五、源码分析与不足

首先我们来分析一下框架执行的大致流程:
index.php(入口、调试模式、应用路径)
–> ThinkPHP.php(定义路径与访问模式)
–> Think\Think(类加载器、异常处理、读取共有配置)
–> Think\App(请求url调度解析、执行调度解析结果)
–> exec 执行用户定义的Controller的Action方法
–> Think\Dispatcher(根据url模式解析M、C、A和参数,加载模块配置)
–> Think\Controller(调用视图、包装和重定向)
可以看到,框架的内部流程其实比较简单,还有2个很重要的类:
Think\Hook: 监听App、Action、View的各个阶段,执行Behavior
Think\Behavior: 可配置(配置文件)可增删(代码)

在分析源代码的过程中,我们也看到了一些不足:

1、宏定义过多,难于维护和修改
建议:只在个别文件定义极少数几个宏,其余用类常量包装
2、面向过程代码过多,封装不清晰
建议:用面向对象思想包装
例如:url的解析和包装,现在是在Dispatcher里生成APP宏,然后在U方法里读取宏并生成最终url。其实完全可以定义一个类来包装例如UrlHelper,而类的二个方法parse和generate分别负责解析和生成url,这样代码结构会清晰很多。
3、有的函数和类代码封装过多,复用和改进不方便
建议:用组合来封装独立功能内容
例如:Model的校验功能,完全可以独立成类,也可以用于非Model对象调用。而现在的校验接口是Model的保护性方法,只能在Model的create函数调用,外面必须通过create方法才能校验。
4、代码规范和风格问题
希望代码风格能更加规范和标准,例如DB类作为模板方法的父类,应该用抽象方法或抛出异常形式定义所有Model需用到的方法。事实上有些方法子类是不需要的,而Db类却没有实现。

六、总结

ThinkPHP作为国内热门的php框架,确实给我们的开发带来了便利。框架开发者对web流程理解的很透彻,对php的函数应用炉火纯青。框架定义了灵活的配置和扩展适应各种需求,提供了丰富的组件和模块来加速开发。最后说一点,ThinkPHP的文档和社区支持非常完善,这也是框架流行不可缺少的重要一环。我们也希望ThinkPHP以后能更加完善自身的结构,打造成最优秀的php框架。



推荐阅读
  • MVC设计模式的介绍和演化过程
    本文介绍了MVC设计模式的基本概念和原理,以及在实际项目中的演化过程。通过分离视图、模型和控制器,实现了代码的解耦和重用,提高了项目的可维护性和可扩展性。详细讲解了分离视图、分离模型和分离控制器的具体步骤和规则,以及它们在项目中的应用。同时,还介绍了基础模型的封装和控制器的命名规则。该文章适合对MVC设计模式感兴趣的读者阅读和学习。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • 后台获取视图对应的字符串
    1.帮助类后台获取视图对应的字符串publicclassViewHelper{将View输出为字符串(注:不会执行对应的ac ... [详细]
  • Todayatworksomeonetriedtoconvincemethat:今天在工作中有人试图说服我:{$obj->getTableInfo()}isfine ... [详细]
  • SpringBoot简单日志配置
     在生产环境中,只打印error级别的错误,在测试环境中,可以调成debugapplication.properties文件##默认使用logbacklogging.level.r ... [详细]
  • 本文详细介绍了SQL日志收缩的方法,包括截断日志和删除不需要的旧日志记录。通过备份日志和使用DBCC SHRINKFILE命令可以实现日志的收缩。同时,还介绍了截断日志的原理和注意事项,包括不能截断事务日志的活动部分和MinLSN的确定方法。通过本文的方法,可以有效减小逻辑日志的大小,提高数据库的性能。 ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • Metasploit攻击渗透实践
    本文介绍了Metasploit攻击渗透实践的内容和要求,包括主动攻击、针对浏览器和客户端的攻击,以及成功应用辅助模块的实践过程。其中涉及使用Hydra在不知道密码的情况下攻击metsploit2靶机获取密码,以及攻击浏览器中的tomcat服务的具体步骤。同时还讲解了爆破密码的方法和设置攻击目标主机的相关参数。 ... [详细]
  • 本文介绍了使用PHP实现断点续传乱序合并文件的方法和源码。由于网络原因,文件需要分割成多个部分发送,因此无法按顺序接收。文章中提供了merge2.php的源码,通过使用shuffle函数打乱文件读取顺序,实现了乱序合并文件的功能。同时,还介绍了filesize、glob、unlink、fopen等相关函数的使用。阅读本文可以了解如何使用PHP实现断点续传乱序合并文件的具体步骤。 ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • IOS开发之短信发送与拨打电话的方法详解
    本文详细介绍了在IOS开发中实现短信发送和拨打电话的两种方式,一种是使用系统底层发送,虽然无法自定义短信内容和返回原应用,但是简单方便;另一种是使用第三方框架发送,需要导入MessageUI头文件,并遵守MFMessageComposeViewControllerDelegate协议,可以实现自定义短信内容和返回原应用的功能。 ... [详细]
  • Asp.net Mvc Framework 七 (Filter及其执行顺序) 的应用示例
    本文介绍了在Asp.net Mvc中应用Filter功能进行登录判断、用户权限控制、输出缓存、防盗链、防蜘蛛、本地化设置等操作的示例,并解释了Filter的执行顺序。通过示例代码,详细说明了如何使用Filter来实现这些功能。 ... [详细]
  • 本文介绍了ASP.NET Core MVC的入门及基础使用教程,根据微软的文档学习,建议阅读英文文档以便更好理解,微软的工具化使用方便且开发速度快。通过vs2017新建项目,可以创建一个基础的ASP.NET网站,也可以实现动态网站开发。ASP.NET MVC框架及其工具简化了开发过程,包括建立业务的数据模型和控制器等步骤。 ... [详细]
author-avatar
hustjs
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有