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

ThinkPHP3.1快速入门(11)控制器高级特性

ThinkPHP的控制器层由核心控制器和业务控制器组成,核心控制器由系统内部的App类完成,负责应用(包括模块和操作)的调度控制,包括HTTP请求拦截和转发、加载配置等,业务控制器则由用户定义的Action类或者其他控制器类完成。
ThinkPHP的控制器层由核心控制器和业务控制器组成,核心控制器由系统内部的App类完成,负责应用(包括模块和操作)的调度控制,包括HTTP请求拦截和转发、加载配置等,业务控制器则由用户定义的Action类或者其他控制器类完成。
我们通过前面的学习,已经了解了基本的控制器用法,这一篇我们来讲述下控制器的一些特性和高级用法,来探索ThinkPHP控制器的神秘外衣。[-more-]

Action参数绑定

在前面的内容中,我们涉及的所有操作方法都是没有任何参数的,其实从3.1版本开始,可以支持参数绑定功能。Action参数绑定的原理是把URL中的参数(不包括分组、模块和操作名)和控制器的操作方法中的参数(按变量名)进行绑定。
例如,我们给Blog模块定义了两个操作方法read和archive方法,并且给read操作需要指定一个id参数,archive方法指定年份(year)和月份(month)两个参数。为了演示方便,我们省去了具体操作方法的业务代码,仅仅用echo 输出当前的参数。
  1. class BlogAction extends Action{
  2.     public function read($id){
  3.         echo 'id='.$id;
  4.     }
  5.   
  6.     public function archive($year='2012',$month='01'){
  7.         echo 'year='.$year.'&mOnth='.$month;
  8.     }
  9. }
URL的访问地址分别是:
  1. http://serverName/index.php/Blog/read/id/5
  2. http://serverName/index.php/Blog/archive/year/2012/month/03
两个URL地址中的id参数和year和month参数会自动和read操作方法以及archive操作方法的同名参数绑定。
输出的结果依次是:
  1. id=5
  2. year=2012&month=03
Action参数绑定的参数必须和URL中传入的参数名称一致,但是参数顺序不需要一致。也就是说
  1. http://serverName/index.php/Blog/archive/month/03/year/2012
和上面的访问结果是一致的,URL中的参数顺序和操作方法中的参数顺序都可以随意调整,关键是确保参数名称一致即可。
如果用户访问的URL地址是(至于为什么会这么访问暂且不提):
  1. http://serverName/index.php/Blog/read/
那么会抛出下面的异常提示:
  1. 参数错误:id
报错的原因很简单,因为在执行read操作方法的时候,id参数是必须传入参数的,但是方法无法从URL地址中获取正确的id参数信息。由于我们不能相信用户的任何输入,因此建议你给read方法的id参数添加默认值,例如:
  1. public function read($id=0){
  2.     echo 'id='.$id;
  3. }
这样,当我们访问
  1. http://serverName/index.php/Blog/read/
的时候 就会输出
  1. id=0
当我们访问
  1. http://serverName/index.php/Blog/archive/
的时候,输出:
  1.  year=2012&month=01
参数绑定功能不受路由影响,从路由中匹配和URL传入的参数一样有效,并且绑定的参数如果需要特殊处理和过滤的话,需要另行处理。


空模块和空操作

空操作是指系统在找不到指定的操作方法的时候,会定位到空操作(_empty)方法来执行,利用这个机制,我们可以实现错误页面和一些URL的优化。
例如,下面我们用空操作功能来实现一个城市切换的功能。
我们只需要给CityAction类定义一个_empty (空操作)方法:
  1. php
  2. class CityAction extends Action{
  3.     public function _empty($name){
  4.        //把所有城市的操作解析到city方法
  5.        $this->city($name);
  6.     }
  7.             
  8.     //注意 city方法 是 protected 方法
  9.     protected function city($name){
  10.         //和$name这个城市相关的处理
  11.         echo '当前城市' $name;
  12.      }
  13. }
接下来,我们就可以在浏览器里面输入
  1. http://serverName/index.php/City/beijing/
  2. http://serverName/index.php/City/shanghai/
  3. http://serverName/index.php/City/shenzhen/
由于CityAction并没有定义beijing、shanghai或者shenzhen操作方法,因此系统会定位到空操作方法 _empty中去解析,_empty方法的参数就是当前URL里面的操作名,因此会看到依次输出的结果是:
  1. 当前城市:beijing
  2. 当前城市:shanghai
  3. 当前城市:shenzhen
空模块的概念是指当系统找不到指定的模块名称的时候,系统会尝试定位空模块(EmptyAction),利用这个机制我们可以用来定制错误页面和进行URL的优化。现在我们把前面的需求进一步,把URL由原来的
  1. http://serverName/index.php/City/shanghai/
变成
  1. http://serverName/index.php/shanghai/
这样更加简单的方式,如果按照传统的模式,我们必须给每个城市定义一个Action类,然后在每个Action类的index方法里面进行处理。 可是如果使用空模块功能,这个问题就可以迎刃而解了。 我们可以给项目定义一个EmptyAction类
  1. php
  2. class EmptyAction extends Action{
  3.     public function index(){
  4.         //根据当前模块名来判断要执行那个城市的操作
  5.         $cityName = MODULE_NAME;
  6.         $this->city($cityName);
  7.     }
  8.    //注意 city方法 本身是 protected 方法
  9.    protected function city($name){
  10.        //和$name这个城市相关的处理
  11.        echo '当前城市' $name;
  12.     }
  13. }
接下来,我们就可以在浏览器里面输入
  1. http://serverName/index.php/beijing/
  2. http://serverName/index.php/shanghai/
  3. http://serverName/index.php/shenzhen/
由于系统并不存在beijing、shanghai或者shenzhen模块,因此会定位到空模块(EmptyAction)的默认操作(index)去执行,会看到依次输出的结果是:
  1. 当前城市:beijing
  2. 当前城市:shanghai
  3. 当前城市:shenzhen
空模块和空操作还可以同时使用,用以完成更加复杂的操作。

前置和后置操作

如果当前访问的操作是存在的,系统会检测当前操作是否具有前置和后置操作,如果存在就会按照顺序执行,前置和后置操作的方法名是在要执行的方法前面加 _before_和_after_,例如:
  1. class IndexAction extends Action{
  2.     //前置操作方法
  3.     public function _before_index(){
  4.         echo 'before
    '
    ;
  5.     }
  6.     public function index(){
  7.         echo 'index
    '
    ;
  8.     }
  9.     //后置操作方法
  10.     public function _after_index(){
  11.         echo 'after
    '
    ;
  12.     }
  13. }
如果我们访问
  1. http://serverName/index.php
结果会输出
  1. before
  2. index
  3. after
对于任何操作方法我们都可以按照这样的规则来定义前置和后置方法。
需要注意的是,如果在操作方法里面使用了exit或者error方法的话 有可能不会再执行后置方法了。

跳转和重定向

系统的Action类内置了两个页面跳转方法error和success,分别用于错误(提示)跳转和成功(提示)跳转。两个方法都会输出一个提示信息页面,然后自动跳转到指定的地址。如果当前请求是ajax方式的话,则会自动进行ajax数据返回。下面是一个简单的例子:
  1. $User = M('User'); //实例化User对象
  2. $result = $User->add($data); 
  3. if($result){
  4.     //设置成功后跳转页面的地址,默认的返回页面是$_SERVER['HTTP_REFERER']
  5.     $this->success('新增成功''/User/list');
  6. else {
  7.     //错误页面的默认跳转页面是返回前一页,通常不需要设置
  8.     $this->error('新增失败');
  9. }
Success和error方法都有对应的模板,并且是可以设置的,默认的设置是系统模板:
  1. //默认错误跳转对应的模板文件
  2. 'TMPL_ACTION_ERROR' => THINK_PATH 'Tpl/dispatch_jump.tpl',
  3. //默认成功跳转对应的模板文件
  4. 'TMPL_ACTION_SUCCESS' => THINK_PATH 'Tpl/dispatch_jump.tpl',
我们可以在项目配置文件中修改为使用项目内部的模板文件
  1. //默认错误跳转对应的模板文件
  2. 'TMPL_ACTION_ERROR' => 'Public:error',
  3. //默认成功跳转对应的模板文件
  4. 'TMPL_ACTION_SUCCESS' => 'Public:success',
如果你的操作不需要任何提示页面,也可以直接使用页面重定向功能。
系统提供了redirect方法实现页面的重定向功能。
例如:
  1. //重定向到New模块的Category操作
  2. $this->redirect('New/category'array('cate_id' => 2), 5'页面跳转中...');
上面的用法是停留5秒后跳转到New模块的category操作,并且显示页面跳转中字样,重定向后会改变当前的URL地址。
redirect方法的第一个参数和第二个参数的配合来完成实际的URL地址的组装,用法和U函数的用法基本一致。
如果你仅仅是想重定向要一个指定的URL地址,而不是到某个模块的操作方法,可以直接使用redirect函数重定向,例如:
  1. //重定向到指定的URL地址
  2. redirect('/New/category/cate_id/2'5'页面跳转中...');
Redirect方法的第一个参数是要跳转的实际URL地址。

AJAX返回

目前的很多WEB应用中大量运用了ajax操作,系统也提供了一个用于ajax数据返回的方法ajaxReturn方法,用法:
  1. $this->ajaxReturn(返回数据[,返回数据格式]);
目前已经支持的ajax返回数据格式包括:XML JSON JSONP EVAL。
下面是一个简单的例子:
  1. $data['status'] = 1;
  2. $data['info'] = 'info';
  3. $data['data'] = $data;
  4. $data['url'] = $url;
  5. $this->ajaxReturn($data);
在客户端就可以接收传递的$data数据,可以通过ajaxReturn方法传递任意数据到客户端。如果不指定返回格式的话,默认为JSON格式返回,也可以指定数据格式返回:
  1. $this->ajaxReturn($data,'XML');
页面跳转方法success和error如果在ajax请求方式下面会自动调用ajaxReturn方法,例如:
  1. $this->success('发布成功',$url);
等效于使用:
  1. $data['info'] = '发布成功';
  2. $data['url']    = $url;
  3. $data['status'] = 1;
  4. $this->ajaxReturn($data);
在客户端就可以接收返回的包含info、url和status值的data数据。

你无需担心客户端怎么发送ajax请求给ThinkPHP,ThinkPHP可以自动识别大部分类库的ajax请求,包括JqueryAjax,但某些Flash上传组件可能无法准确识别,请确保在请求的URL地址中传入ajax=1参数,这样就能让ThinkPHP识别为Ajax操作。

页面请求类型

如果需要根据当前的页面请求类型来做出不同的处理,可以使用系统提供的几个常量:
REQUEST_METHOD 当前请求类型
IS_GET 是否GET请求
IS_POST 是否POST请求
IS_PUT 是否PUT请求
IS_DELETE 是否DELETE请求
IS_AJAX 是否AJAX请求
举例如下:
  1. class UserAction extends Action{
  2.     public function update(){
  3.         if (IS_POST){
  4.             $User = M('User');
  5.             $User->create();
  6.             $User->save();
  7.             $this->success('保存完成');
  8.         }else{
  9.             $this->error('非法请求');
  10.         }
  11.     }
  12. }

伪静态

默认情况下,ThinkPHP可以支持所有的静态后缀,并且会记录当前的伪静态后缀到常量__EXT__,但不会影响正常的页面访问。
例如:
  1. http://serverName/User/3.html
  2. http://serverName/User/3.shtml
  3. http://serverName/User/3.xml
  4. http://serverName/User/3.pdf
都可以正常访问,如果要获取当前访问的伪静态后缀,通过常量__EXT__获取即可。
如果希望统一伪静态后缀,可以设置:
  1. 'URL_HTML_SUFFIX'=>'html'
现在则只能访问
  1. http://serverName/User/3.html
也可以支持允许多个后缀,例如:
  1. 'URL_HTML_SUFFIX'=>'html|shtml|xml' // 多个用 | 分割
这样,当访问http://serverName/User/3.pdf的时候会报系统错误。
是实际应用中,我们可以根据当前的URL访问后缀来做出不同的输出处理。

多层控制器

3.1版本开始增加了多层业务控制器的支持,给中大型应用提供了方便,例如我们可以分为业务控制器和事件控制器:
  1. Action/UserAction //用于用户的业务逻辑控制和调度
  2. Event/UserEvent //用于用户的事件响应操作
UserAction负责外部交互响应,通过URL请求响应,例如 http://serverName/User/index,而UserEvent 负责内部的事件响应,并且只能在内部调用
  1.  A('User','Event');
所以是和外部隔离的。多层控制器的划分也不是强制的,可以根据项目的需要自由分层。控制器分层里面可以根据需要调用分层模型,也可以调用不同的目录的视图模板。

总结

本篇涉及到的ThinkPHP的控制器特性包括空模块和空操作、前置和后置操作、参数绑定、伪静态、跳转和重定向、ajax返回、请求类型,而新版的多层控制器的特性更是值得回味。

推荐阅读
  • IT方面的论坛太多了,有综合,有专业,有行业,在各个论坛里混了几年,体会颇深,以前是论坛哪里人多 ... [详细]
  • GetWindowLong函数
    今天在看一个代码里头写了GetWindowLong(hwnd,0),我当时就有点费解,靠,上网搜索函数原型说明,死活找不到第 ... [详细]
  • CEPH LIO iSCSI Gateway及其使用参考文档
    本文介绍了CEPH LIO iSCSI Gateway以及使用该网关的参考文档,包括Ceph Block Device、CEPH ISCSI GATEWAY、USING AN ISCSI GATEWAY等。同时提供了多个参考链接,详细介绍了CEPH LIO iSCSI Gateway的配置和使用方法。 ... [详细]
  • PHP玩家基地系统毕业设计(附源码、运行环境)的用户登录界面、游戏管理和玩家作品管理
    本文介绍了一个PHP玩家基地系统的毕业设计,包括用户登录界面、游戏管理和玩家作品管理等功能。附带源码和运行环境,并提供免费赠送本源代码和数据库的方式,请私信获取详细信息。摘要共计约XXX字。 ... [详细]
  • 使用在线工具jsonschema2pojo根据json生成java对象
    本文介绍了使用在线工具jsonschema2pojo根据json生成java对象的方法。通过该工具,用户只需将json字符串复制到输入框中,即可自动将其转换成java对象。该工具还能解析列表式的json数据,并将嵌套在内层的对象也解析出来。本文以请求github的api为例,展示了使用该工具的步骤和效果。 ... [详细]
  • HDFS2.x新特性
    一、集群间数据拷贝scp实现两个远程主机之间的文件复制scp-rhello.txtroothadoop103:useratguiguhello.txt推pushscp-rr ... [详细]
  • 仙贝旅行是日本最大的旅游服务平台之一,为广大用户提供优质的日本定制游服务。随着用户数量的增长,仙贝旅行决定与智齿科技合作,全面替换原有客服系统,打造全新的在线客服体系。该体系具备多渠道快速接入的能力,让仙贝旅行轻松与各个渠道的接入用户完成沟通。同时,机器人与人工协同发力,提升客户服务水平。 ... [详细]
  • 本文介绍了一些Java开发项目管理工具及其配置教程,包括团队协同工具worktil,版本管理工具GitLab,自动化构建工具Jenkins,项目管理工具Maven和Maven私服Nexus,以及Mybatis的安装和代码自动生成工具。提供了相关链接供读者参考。 ... [详细]
  • 本文由编程笔记#小编为大家整理,主要介绍了StartingzookeeperFAILEDTOSTART相关的知识,希望对你有一定的参考价值。下载路径:https://ar ... [详细]
  • ubuntu用sqoop将数据从hive导入mysql时,命令: ... [详细]
  • 本文介绍了在Linux下安装和配置Kafka的方法,包括安装JDK、下载和解压Kafka、配置Kafka的参数,以及配置Kafka的日志目录、服务器IP和日志存放路径等。同时还提供了单机配置部署的方法和zookeeper地址和端口的配置。通过实操成功的案例,帮助读者快速完成Kafka的安装和配置。 ... [详细]
  • SAP羞辱国产软件商:技术停在10年前
    SAP中国研究院总裁芮祥麟表示,国产软件厂商过于热衷概念炒作,技术水平停留在10年前的客户端架构水平。他认为,国内厂商推出基于SOA的产品或转型SAAS模式是不可能的,研发新架构需要时间。当前最热门的概念是云计算,芮祥麟呼吁国产厂商应该潜心研发底层架构。 ... [详细]
  • 本文讲述了孙悟空写给白骨精的信件引发的思考和反省。孙悟空在信中对自己的行为进行了反思,认识到自己胡闹的行为并没有给他带来实际的收获。他也揭示了西天取经的真相,认为这是玉皇、菩萨设下的一场陷阱。他还提到了师傅的虚伪和对自己的实心话,以及自己作为师傅准备提拔的对象而被派下来锻炼的经历。他认为路上的九九八十一难也都是菩萨算计好的,唐僧并没有真正的危险。最后,他提到了观音菩萨在关键时刻的指导。这封信件引发了孙悟空对自己行为的思考和反省,对西天取经的目的和自己的角色有了更深入的认识。 ... [详细]
  • Windows2003 IIS上设置301定向,实现不带www域名跳转带www域名的方法
    打开IIS,建一个网站,主机头用不带www的域名,随便指向一个目录。然后在这个网站上点右键,属性--主目录--重定向到URL如图ÿ ... [详细]
  • Postgresql备份和恢复的方法及命令行操作步骤
    本文介绍了使用Postgresql进行备份和恢复的方法及命令行操作步骤。通过使用pg_dump命令进行备份,pg_restore命令进行恢复,并设置-h localhost选项,可以完成数据的备份和恢复操作。此外,本文还提供了参考链接以获取更多详细信息。 ... [详细]
author-avatar
Lyj眼淚啲菋噵
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有