# 快速入门(十八):多层控制器 ThinkPHP支持多层业务控制器的支持,给中大型应用提供了方便。 ## 定义多层控制器 我们通常所了解的控制器其实是Controller控制器类,而且大多数也是继承了核心的Think\Controller类,由于该类控制器是通过URL访问请求后调用的,因此也称之为访问控制器,事实上,ThinkPHP可以支持更多的控制器分层,多层控制器的定义完全取决于项目的需求,例如我们可以分为业务控制器和事件控制器: > Home\Controller\UserController //用于用户的业务逻辑控制和调度 > Home\Event\UserEvent //用于用户的事件响应操作 ~~~ ├─Controller 访问控制器 │ ├─UserController.class.php │ ... ├─Event 事件控制器 │ ├─UserEvent.class.php │ ... ~~~ 一个标准的访问控制器定义如下: ~~~ namespace Home\Controller; class UserController extend Think\Controller { // 默认操作方法 public function index(){ //... } // 用户注册操作方法 public function register(){ //... } } ~~~ > 注:访问控制器的名称并非一定是Controller,而是通过DEFAULT_C_LAYER设置的,默认设置是Controller。 访问控制器负责外部的交互响应,通过URL请求调用,例如: ~~~ http://serverName/Home/User/index http://serverName/Home/User/register ~~~ 而事件控制器负责内部的事件响应,并且只能在内部调用,所以是和外部隔离的。 > 确切的说,所有访问控制器之外的分层控制器都只能内部实例化调用。 ~~~ namespace Home\Event; class UserEvent { // 用户登录事件 public function login(){ echo 'login event'; } // 用户登出事件 public function logout(){ echo 'logout event'; } } ~~~ > 如果是定义其他的控制器层,则不一定必须要继承系统的Controller类或其子类,通常需要输出模版的时候才需要继承Controller类。 ## 调用多层控制器 访问控制器是通过URL请求调用,访问控制器之外的分层控制器都只能内部调用,调用多层控制器可以通过两种方式: ### 直接实例化 ~~~ namespace Home\Controller; class UserController extend Think\Controller { // 默认操作方法 public function index(){ // 触发事件 $event = new \Home\Event\UserEvent(); $event->login(); } } ~~~ ### A函数实例化 ~~~ namespace Home\Controller; class UserController extend Think\Controller { // 默认操作方法 public function index(){ // 触发事件 $event = A('User','Event'); $event->login(); // 或者直接使用 // R('User/login','','Event'); } } ~~~ ## Widget实例 Widget类的实现可以作为分层控制器的另外一个典型实例。 举个例子,我们在页面中实现一个分类菜单的Widget,首先我们要定义一个Widget控制器层 MenuWidget,如下: ~~~ namespace Home\Widget; class MenuWidget extends Think\Controller { public function index(){ echo 'menuWidget'; } } ~~~ 类文件位于 `Home/Widget/MenuWidget.class.php`。 然后,我们在需要显示分类菜单的模版中通过W方法调用这个Widget。 ~~~ {~W('Menu/index')} ~~~ 执行后的输出结果是: menuWidget 如果需要在调用Widget的时候传入参数,可以这样定义: ~~~ namespace Home\Widget; class MenuWidget extends Think\Controller { public function index($id,$name){ echo $id.':'.$name; } } ~~~ 在需要显示分类菜单的模版中添加如下的Widget调用代码如下: ~~~ {~W('Menu/index',array(5,'thinkphp'))} ~~~ 则会输出 5:thinkphp 来一个复杂一点的例子: ~~~ namespace Home\Widget; class MenuWidget extends Think\Controller { public function index(){ $menu = M('Cate')->getField('id,title'); $this->assign('menu',$menu); $this->display('Widget/menu'); } } ~~~ CateWiget类渲染了一个模版文件 `Home/View/Widget/menu.html`, 在menu.html模版文件中的用法: ~~~ <foreach name="menu" item="title"> {$key}:{$title} </foreach> ~~~