ThinkPHP框架设计与扩展总结

原文详见:http://www.ucai.cn/blogdetail/7028?mid=1
还能在线运行查看效果哦php

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

1、框架分层及url路由
框架的安装很是简单,下载后放入web服务器的目录便可,可是建议你们不要用默认的入口文件位置,而是放入单独的目录,便于保护代码和数据。例如个人入口文件和web服务器配置目录在web目录(外层框架里的index.php没有删除可是没有使用):
请输入图片描述html

同大多数MVC框架同样,咱们只须要按框架的目录结构,扩展本身的Controller和View,一些页面就开发完成了。ThinkPHP提供Module、Controller、Action三层结构来组织本身的url(3.1版本叫分组、Action和method,3.2更加国际范),目录结构以下:
请输入图片描述mysql

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

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

好处是复用性好,假如未来要开发wap页面,写了不一样的Controller,就能够复用service,假如之后的数据存储变了,好比把数据库从mysql迁移到mongodb之类,那修改Model就能够,service仍是不须要任何修改。
二、基础模块和业务模块分开,不要相互引用。基础模块(例如用户基本信息)只提供数据接口没有Controller和View。
三层目录已经能够应对通常的web应用,更加复杂的web应用咱们能够定义不一样的入口文件加载不一样的Application来解决。更更复杂的应用?门户和超大规模网站么,那就不是一个php框架能解决全部问题的了,须要本身的中间件和定制框架。正则表达式

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

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

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

到这里咱们能够看到,ThinkPHP框架支持的层次结构和url配置很是丰富,能知足各类不一样的需求。固然咱们建议你们不要滥用路由配置,适当少许的配置能带来更好的seo效果,可是大量的配置会给项目的维护和修改带来困难。shell

2、ThinkPHP扩展
ThinkPHP自己含有丰富的组件和驱动,咱们以数据库驱动扩展和行为扩展为例来了解一下ThinkPHP的扩展设计。数据库

3、数据库驱动扩展
虽然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'], $str);
        exec($cmd, $arr);
}

固然这个只是示例,ThinkPHP自己就支持sqlite3,经过pdo的方式去链接就能够。实际的应用环境多是经过链接4层协议访问中间层端口获取数据。

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提供了很灵活的扩展和加强机制,能知足众多需求。其余存储、缓存、日志、模板引擎等若是须要也能很方便的扩展。

5、源码分析与不足
首先咱们来分析一下框架执行的大体流程:
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: 可配置(配置文件)可增删(代码)

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

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

相关文章
相关标签/搜索