热门标签 | 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返回、请求类型,而新版的多层控制器的特性更是值得回味。

推荐阅读
  • 随着科技的进步,AR智能眼镜正逐渐成为日常生活的一部分。今年冬天,一款仅重38克的AR智能眼镜成为了市场上的焦点,其超轻设计和创新功能值得我们深入了解。 ... [详细]
  • 本文探讨了为何DataWindow.NET在PowerBuilder 11之后版本中不再被支持,并提供了一种在PB12.5中恢复此功能的解决方案。欢迎交流与反馈。 ... [详细]
  • 每位开发者都应该拥有一个展示自我技能与分享知识的空间——个人技术博客。本文将指导你如何使用静态网站生成器Hexo结合GitHub Pages搭建这样一个平台。 ... [详细]
  • APP数据包捕获挑战
    本文探讨了在使用Burp Suite捕获移动应用数据包时遇到的两大难题,尤其是SSL Pinning安全机制的影响,并提供了一种解决方案。 ... [详细]
  • 本文深入探讨了JavaScript中原型(prototype)、构造函数以及对象实例之间的关系,并通过实例分析了它们如何相互作用以实现代码复用和继承。 ... [详细]
  • 在安装Ubuntu 12.04后,用户可能会遇到系统菜单中缺少休眠(Hibernate)选项的问题。这通常是由于某些程序的错误导致系统默认禁用了此功能。本文将详细介绍如何恢复和使用休眠选项。 ... [详细]
  • 解决ArcEngine中IEngineEditor编辑ArcSDE数据时遇到的0x8004021F错误
    本文探讨了一款自定义GIS插件系统从Personal GeoDatabase迁移到ArcSDE数据源过程中遇到的编辑错误,详细分析了错误原因及解决策略。 ... [详细]
  • 本文介绍了如何从给定的JSON响应中正确地提取产品标题等信息。 ... [详细]
  • 在软件开发领域,测试是确保产品质量的关键环节。本文旨在深入探讨两种特定的测试方法——冒烟测试与随机测试,解析它们的特点、实施方式及应用场景。 ... [详细]
  • Python linecache模块:高效读取文件特定行
    linecache模块提供了一种简便的方法来快速访问文件中的特定行,无需通过复杂的文件操作流程。用户只需导入该模块并调用相关方法即可轻松获取所需信息。 ... [详细]
  • 使用LINQ优化WinForms中CheckedListBox的操作
    本文介绍如何利用LINQ扩展方法解决WinForms中CheckedListBox控件的常见操作问题,包括获取选中项的文本并用分隔符连接,以及根据字符串初始化选中状态。 ... [详细]
  • 本文介绍如何使用ShlObj单元中的ShAddToRecentDoc函数,将指定路径的文档添加到Windows系统的最近使用列表中,具体实现包括调用方法和参数设置。 ... [详细]
  • 深入探讨LINQ分组查询
    本文通过具体示例详细解析了LINQ中的分组查询功能,包括如何使用`group by`语句对数据进行分组,并讨论了不同分组查询方式的结果差异。 ... [详细]
  • 深入解析C语言中的sizeof操作符陷阱
    本文通过一个具体的例子探讨了C语言中sizeof操作符的使用陷阱,并详细分析了导致程序行为异常的原因。 ... [详细]
  • 作为一名新手,最近接到的任务是将动网论坛迁移到公司内部网站,并将数据库支持从Access调整为Oracle。虽然之前没有接触过Oracle,但在实际操作过程中遇到了一些技术挑战,如Oracle中自增ID的实现方式等。 ... [详细]
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社区 版权所有