Yii2创建控制器(createController)方法详解


Posted in PHP onJuly 23, 2016

本文实例讲述了Yii2创建控制器(createController)方法。分享给大家供大家参考,具体如下:

yii中创建控制器的是在application中的request通过UrlManager解析得出路由信息的,然后再由yii\base\Module中的

public function runAction($route, $params = [])

方法来创建控制器,最后由控制器再执行相应的动作。

首先得明确,Yii中的路由分三种情况:

第一种是带有模块的(module id/controller id/action id),

第二种是带有命名空间(子目录)的(sub dir)/controller id/action id)

第三种是只有控制器和动作的(controller id/action id)

这三个有优先顺序,所以在创建控制器的时候,也是先查看是否是模块类型的路由,如果是,则获取这个模块,再由这个模块来创建控制器

接着再判断是否是第二种带有命名空间的。

public function createController($route)
{
  //如果路由为空,则使用默认的路由
  if ($route === '') {
    $route = $this->defaultRoute;
  }
  // double slashes or leading/ending slashes may cause substr problem
  //去掉首尾的反斜杠(“/”),如果路由中包含有“//”,则返回false创建失败。
  $route = trim($route, '/');
  if (strpos($route, '//') !== false) {
    return false;
  }
  /*
   * 路由分三种情况,
   * 一种是带模块id的(module id/controller id/action id),
   * 一种是有命名空间(子目录)的(sub dir)/controller id/action id)
   * 一种是只有控制器和动作的(controller id/action id)
   * 所以在这里要根据第一个“/”分隔成两部分,$id和$route信息,
   */
  if (strpos($route, '/') !== false) {
    list ($id, $route) = explode('/', $route, 2);
  } else {
    $id = $route;
    $route = '';
  }
  // module and controller map take precedence
  /*
   * 查看这个id是否是模块,如果是模块,则再用这个模块来创建控制器。
   * 所以,在如果一个控制器的名称和模块名称重复的话会优先创建模块里面的控制器。
   *
   * 如果有url: http://www.yii2.com/index.php?r=test/index
   * 本来是打算访问application中的控制器里面的test控制器,执行index动作的。
   *
   * 然而如果有个模块的名字为test,里面有个IndexController
   *
   * 根据上面会生成$id=test,$route=index
   *
   * 由于在下面查找存在这个模块,所以会执行这个test模块下面的index控制器,
   * 而不会执行application里面的test控制器的index动作
   */
  $module = $this->getModule($id);
  if ($module !== null) {
    return $module->createController($route);
  }
  //如果在controllerMap数组中指定了控制器映射,会优先根据这个里面的映射来创建控制器
  if (isset($this->controllerMap[$id])) {
    $controller = Yii::createObject($this->controllerMap[$id], [$id, $this]);
    return [$controller, $route];
  }
  /*
   * 如果这个时候$route中还有“/”,也就是说原来的路由为home/index/aa
   * $id:home(不是模块)
   * $route:index/aa
   * 由于经过上面得知home不为模块,所以这个为命名空间(子目录),
   *
   * 再经过下面处理后为
   * $id:home/index 命名空间(子目录)home下面的index控制器
   * $route:aaa
   *
   */
  if (($pos = strrpos($route, '/')) !== false) {
    $id .= '/' . substr($route, 0, $pos);
    $route = substr($route, $pos + 1);
  }
    /*
     * $id:home/index
     * $route:aaa
     */
  $controller = $this->createControllerByID($id);
  if ($controller === null && $route !== '') {
      //如果创建失败,再加上route作为id再次创建
    $controller = $this->createControllerByID($id . '/' . $route);
    $route = '';
  }
  return $controller === null ? false : [$controller, $route];
}

在这个函数中$id就有两种情况,一种是前面带有命名空间的,一种是直接就一个控制器ID的。

public function createControllerByID($id)
{
    if (!preg_match('%^[a-z0-9\\-_/]+$%', $id)) {
      return null;
    }
    /*
     * 如果$id中有“/”,则前面的为目录,后面的为类
     *
     */
    $pos = strrpos($id, '/');
    if ($pos === false) {
      $prefix = '';
      $className = $id;
    } else {
      $prefix = substr($id, 0, $pos + 1);
      $className = substr($id, $pos + 1);
    }
    //生成控制器的类IndexController
    $className = str_replace(' ', '', ucwords(str_replace('-', ' ', $className))) . 'Controller';
    //如果有前缀(也就是有目录、命名空间),则在类前面加上命名空间
    $className = ltrim($this->controllerNamespace . '\\' . str_replace('/', '\\', $prefix) . $className, '\\');
    //如果类不存在,或者类名称包含“-”,则出错,
    if (strpos($className, '-') !== false || !class_exists($className)) {
      return null;
    }
    //下面就是创建类了
    if (is_subclass_of($className, 'yii\base\Controller')) {
      return new $className($id, $this);
    } elseif (YII_DEBUG) {
      throw new InvalidConfigException("Controller class must extend from \\yii\\base\\Controller.");
    } else {
      return null;
    }
}

这个过程就结束了,然后再由创建出来的控制器执行它里面的动作

public function runAction($route, $params = [])
{
  $parts = $this->createController($route);
  if (is_array($parts)) {
    /** @var Controller $controller */
    list($controller, $actionID) = $parts;
    $oldController = Yii::$app->controller;
    Yii::$app->controller = $controller;
    //控制器执行相应的动作
    $result = $controller->runAction($actionID, $params);
    Yii::$app->controller = $oldController;
    return $result;
  } else {
    $id = $this->getUniqueId();
    throw new InvalidRouteException('Unable to resolve the request "' . ($id === '' ? $route : $id . '/' . $route) . '".');
  }
}

希望本文所述对大家基于Yii框架的PHP程序设计有所帮助。

PHP 相关文章推荐
PHP时间戳使用实例代码
Jun 07 PHP
谈谈新手如何学习PHP 默默经典版本
Aug 04 PHP
php中修改浏览器的User-Agent来伪装你的浏览器和操作系统
Jul 29 PHP
深入PHP empty(),isset(),is_null()的实例测试详解
Jun 06 PHP
实测在class的function中include的文件中非php的global全局环境
Jul 15 PHP
php将access数据库转换到mysql数据库的方法
Dec 24 PHP
19个Android常用工具类汇总
Dec 30 PHP
php字符串过滤与替换小结
Jan 26 PHP
PHP实现懒加载的方法
Mar 07 PHP
php中使用gd库实现远程图片下载实例
May 12 PHP
PHP实现连接设备、通讯和发送命令的方法
Oct 13 PHP
实例讲解如何在PHP的Yii框架中进行错误和异常处理
Mar 17 PHP
Yii2主题(Theme)用法详解
Jul 23 #PHP
Yii2创建表单(ActiveForm)方法详解
Jul 23 #PHP
Yii2验证器(Validator)用法分析
Jul 23 #PHP
yii2 RBAC使用DbManager实现后台权限判断的方法
Jul 23 #PHP
Yii2简单实现多语言配置的方法
Jul 23 #PHP
yii2控制器Controller Ajax操作示例
Jul 23 #PHP
PHP实现清除MySQL死连接的方法
Jul 23 #PHP
You might like
一个基于PDO的数据库操作类
2011/03/24 PHP
php集成环境xampp中apache无法启动问题解决方案
2014/11/18 PHP
ThinkPHP控制器详解
2015/07/27 PHP
JavaScript 学习笔记(九)call和apply方法
2010/01/11 Javascript
jquery中this的使用说明
2010/09/06 Javascript
用JavaScript计算在UTF-8下存储字符串占用字节数
2013/08/08 Javascript
jquery对单选框,多选框,文本框等常见操作小结
2014/01/08 Javascript
nodejs npm install全局安装和本地安装的区别
2014/06/05 NodeJs
JavaScript中对象property的删除方法介绍
2014/12/30 Javascript
JavaScript框架是什么?怎样才能叫做框架?
2015/07/01 Javascript
websocket+node.js实现实时聊天系统问题咨询
2017/05/17 Javascript
JS中的三个循环小结
2017/06/20 Javascript
Vue引用第三方datepicker插件无法监听datepicker输入框的值的解决
2018/01/27 Javascript
js实现轮播图的完整代码
2020/10/26 Javascript
JavaScript中Dom操作实例详解
2019/07/08 Javascript
使用Python的Django框架实现事务交易管理的教程
2015/04/20 Python
Java中重定向输出流实现用文件记录程序日志
2015/06/12 Python
手把手教你用python抢票回家过年(代码简单)
2018/01/21 Python
python截取两个单词之间的内容方法
2018/12/25 Python
python实现植物大战僵尸游戏实例代码
2019/06/10 Python
零基础小白多久能学会python
2020/06/22 Python
Python安装Bs4的多种方法
2020/11/28 Python
selenium+python实现基本自动化测试的示例代码
2021/01/27 Python
纯CSS3绘制打火机动画火焰效果
2016/07/18 HTML / CSS
简单整理HTML5的基本特性和语法
2016/02/18 HTML / CSS
Bailey帽子官方商店:Bailey Hats
2018/09/25 全球购物
2019年Java 最常见的 面试题
2016/10/19 面试题
驾驶员培训方案
2014/05/01 职场文书
环境监测与治理技术专业求职信
2014/07/06 职场文书
群众路线专项整治方案
2014/10/27 职场文书
五四青年节比赛演讲稿
2015/03/18 职场文书
2015年敬老月活动总结
2015/03/27 职场文书
追讨欠款律师函
2015/05/27 职场文书
2016年党员创先争优公开承诺书
2016/03/25 职场文书
python 提取html文本的方法
2021/05/20 Python
golang操作rocketmq的示例代码
2022/04/06 Golang