ThinkPHP官网首页

ENGLISH

Blog

享受TP的DISPATCH功能

发布时间: 2008-12-31 22:54

其实在发表这篇博客的时候,心里很紧张,因为原先答应流年要修改一下本文内容的,结果又没有完成。主要还是由于近日来天天加班,没有什么时间可以定下心来写写东西,因此,文章内容就有点杂乱,而且最终还没有完全结尾,希望大家在看完后不要骂我就行。 同时,今天也是阳历上2008年的最后一天,祝福大家新年快乐 。 附上正文[separator]
----------------------------------我是无耻的分隔线----------------------------------------
 一、背景介绍
   在大多数情况下,为了增加用户体验,实现SEO,我们不得不使用Apache的Rewrite或者IIS的iis_rewrite组件来对URL进行重写,但并非每台服务器都是我们所能控制的。在这种情况下,大多数的程序都通过对PHP自带的$_SERVER['PATH_INFO']或者$_SERVER['REQUEST_URI']变量进行处理,而实现伪rewrite功能。
   目前几乎所有的框架在实现dispatch功能的时候,都是利用了这样的原理,TP也不例外,如果需要查看TP的路由实现,可以查看TP核心目录下的Dispatch.class.php,内部有完整的实现代码,在这里我稍作简单介绍。
二、简单实现
在使用TP的时候,默认就已经打开了dispatch功能。因此在默认生成的代码时,我们是直接在浏览器里使用http://localhost /index.php(1),来进行访问,但其实,默认生成的代码访问全路径应该是http://localhost/index.php/Index/index/(2),为什么通过(1)的地址就可以看到那句经典的:Hello,world呢? 我们打开ThinkPHP目录下的/Common/convertion.php,就可以查看到以下代码:

PHP代码
  1. return array(  
  2.     /* 模块和操作设置 */  
  3.     'DEFAULT_MODULE' => 'Index'// 默认模块名称   
  4.     'DEFAULT_ACTION' => 'index'// 默认操作名称   
  5. );  

  而上文所说的全路径,其实就是因为配置了这个DEFAULT_MODULE和DEFAULT_ACTION。
根据这个配置,我们在项目目录的Lib/Action目录下会发现有一个IndexAction.class.php,这个文件名就是对应 DEFAULT_MODULE'的,如果DEFAULT_MODULE'改为Default,那么相应的,这个 IndexAction.class.php,就应该改名为DefaultAction.class.php。
路径(2)中第二个index,对应的就是DEFAULT_ACTION,打开IndexAction.class.php,你会发现代码是这样定义的: 

PHP代码
  1. // 本类由系统自动生成,仅供测试用途   
  2. class IndexAction extends Action{  
  3.     public function index(){  
  4.         echo'用户首页' );   
  5.     }  
  6. }  

对应上面的代码:class IndexAction extends Action,我们可以知道IndexAction是从基类Action继承而来,而IndexAction这个类名,也是对应于文件名IndexAction.class.php,这样的命名方式也方便了类文件的自动加载和应用。
看到public function index()这个方法没?这个就是对应了刚才所说的DEFAULT_ACTION,如果在路径里没有写上index,那么默认就是调用这个index方法。当然你也可以通过修改配置文件来把这个默认的index改为其他。 看过上面的内容,那么我们应该基本可以从一个URL中知道文件是如何对应的了。例如,http://localhost/index.php/User /getuser/,根据这段代码,那么我们应该知道,它基本是对应于项目目录下/Lib/Action/UserAction.class.php中的 getuser方法。
换句话说,你在该文件里还有一个deluser方法,那么也能通过http://localhost/index.php/User/deluser/来实现。
题外话:虽然这样的方法比较简单易用,但还是有一个基本的要求,对外公开的方法(即可以通过路径访问的方法),请使用public,否则你会得到一条出错信息,大致意思为内部方法或受保护的方法不能被外部直接调用。
三、附加参数
第二节说的只是URL的简单实现,那么如何为这些方法带上相应的参数呢?仍然是查看第二节里提到的convertion.php,在其中有一个变量是这样定义的: 

PHP代码
  1. 'PATH_DEPR' => '/'// PATHINFO参数之间分割号  

  没错,在网页的URL里面变量都是采用了“/”进行分隔,就象上文的index.php/Index/index/一样。 在第二节的例子里面我们提到了index.php/User/getuser/这个方法,如果我们要获取id为1的用户,那么URL就成了 index.php/User/getuser/id/1/这样的实现方式,如果有更多的参数,那么,我们需要做的也就是在URL后面不停的以“键/值” 的方式,采用“/”进行分隔后,追加在上面的URL后面,即最终效果可能是index.php/User/getuser/id/1/username /gouki/lastlogin/1234567890/。 而在代码中则是可以通过$_REQUEST['id']或者$_REQUEST['username']等来获取URL中的变量。$_GET方法也可以,但$_REQUEST所包含的会更多。
四、高级应用
虽然上文中以“/”分隔的应用几乎已经可以满足我们的日常开发需要了,但在实际应用中,为了不让用户猜出我们方法名、变量名等,这样也可以减少被攻击的机会。那么该如何对URL进行配置呢?或许有人会想到了,是的,我仍然会说,请看convertion.php里的配置,确实,流年在convertion 里面进行了很多惯例配置,然而可悲的是,几乎没有几个人会查看这个文件,然后就在论坛里拼命的在问,怎么设置数据库、怎么设置路由,却没有人想到打开这个惯例文件查看一下。 废话不说了,打开该文件,定位到:

PHP代码
  1. /* Dispatch设置 */  
  2. 'DISPATCH_ON' => true, // 是否启用Dispatcher   
  3. 'DISPATCH_NAME' => 'Think'// 默认的Dispatcher名称   
  4. // URL模式: 0 普通模式 1 PATHINFO 2 REWRITE   
  5. 'URL_MODEL' => 1, // 默认为PATHINFO 模式,提供最好的用户体验和SEO支持   
  6. // PATHINFO 模式   
  7. // 普通模式1 参数没有顺序/m/module/a/action/id/1   
  8. // 智能模式2 自动识别模块和操作/module/action/id/1/ 或者 /module,action,id,1/...   
  9. 'PATH_MODEL' => 2, // 默认采用智能模式   
  10. 'PATH_DEPR' => '/'// PATHINFO参数之间分割号   
  11. 'ROUTER_ON' => true, // 启用路由判断   
  12. 'COMPONENT_DEPR' => '@'// 组件模块和操作的URL分割符  

  相信你们都看到了,在惯例文件中,DISPATCH默认已经被打开,而且默认采用的是PATHINFO模式中的智能模式。同时还打开了路由判断。
那么,究竟应该怎么做才能使得我们的URL变得更加的优雅和可变呢? 即使没有使用ROUTER功能,我们也基本上可以使URL更加优雅可变,那就是调整以下四个变量:

PHP代码
  1. /* 系统变量设置 */  
  2. 'VAR_PATHINFO' => 's'// PATHINFO 兼容模式获取变量例如 ?s=/module/action/id/1 后面的参数取决于PATH_MODEL 和 PATH_DEPR   
  3. 'VAR_MODULE' => 'm'// 默认模块获取变量   
  4. 'VAR_ACTION' => 'a'// 默认操作获取变量   
  5. 'VAR_ROUTER' => 'r'// 默认路由获取变量   

通过对这四个变量的调整,即使在没有使用PATHINFO和路由的情况下,我们也能够使用这些变量来应对复杂的URL。但这毕竟是处于初级阶段,详细的我就不作介绍了,因为只要你采用了默认的“键值”对应方式,那么采用对PATH_DEPR进行分割处理,总是可以得到这些相应的值的。 更加强大的操作是TP的路由功能,通过对路由功能的设置,基本上可以达到APACHE的REWRITE功能复杂实现。
让我们先看一个URL,index.php/Category/1,你能猜得出他实现了什么功能吗?
根据上文介绍的方法,或许我们会认为,这是调用了 Category模块下的index方法,但是,这个1是什么意思呢?Id=1?Categoryname = 1?它究竟表达了什么内容?有什么含义?这就需要查看项目目录下Config目录中的routes.php这个文件了,该文件的内容就是TP对于route功能的具体实现。 打开文件后发现有以下内容:

PHP代码
  1. return array(  
  2.     'Category'=>array('Blog','category','id'),   
  3. );  

  看出来是啥意思没?翻开TP的手册(网上可见的,好象就1.0.3的,不过路由功能已经很详细的介绍了)。

PHP代码
  1. // 第一种方式 常规路由   
  2. 'RouteName'=>array('模块名称','操作名称','参数定义','额外参数'),   

  也就是说,上面的定义规则是采用了常规路由,即该URL的实际意义是index.php/Blog/category/id/1,而并非我们想象的是操作Category模块。
综上所述,大家也应该可以对TP的Dispatch功能有一个大致的了解,当然我能力有限,分析的也不够透彻,希望有更多的朋友一起加入TP这个大家庭,来互帮互助。(感觉有些冷,但确实是有这个希望,唉。又抢流年的台词了)

最新动态