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 array_flip() 删除数组重复元素
Jan 14 PHP
收藏的PHP常用函数 推荐收藏保存
Feb 21 PHP
兼容性比较好的PHP生成缩略图的代码
Jan 12 PHP
PHP版国家代码、缩写查询函数代码
Aug 14 PHP
采用thinkphp自带方法生成静态html文件详解
Jun 13 PHP
PHP中遇到BOM、编码导致json_decode函数无法解析问题
Jul 02 PHP
如何让搜索引擎抓取AJAX内容解决方案
Aug 25 PHP
Yii查询生成器(Query Builder)用法实例教程
Sep 04 PHP
PHP+JS三级菜单联动菜单实现方法
Feb 24 PHP
Zend Framework框架实现类似Google搜索分页效果
Nov 25 PHP
phpStudy中升级MySQL版本到5.7.17的方法步骤
Aug 03 PHP
PHP addslashes()函数讲解
Feb 03 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
php adodb连接不同数据库
2009/03/19 PHP
PHP实现事件机制实例分析
2015/06/26 PHP
php中array_multisort对多维数组排序的方法
2020/06/21 PHP
PHP实现文件上传和多文件上传
2015/12/24 PHP
PHP解析url并得到url参数方法总结
2018/10/11 PHP
JavaScript 序列化对象实现代码
2009/12/18 Javascript
JQuery 文本框使用小结
2010/05/22 Javascript
jQuery显示和隐藏 常用的状态判断方法
2015/01/29 Javascript
jQuery验证表单格式的使用方法
2017/01/10 Javascript
ionic实现底部分享功能
2017/05/11 Javascript
Bootstrap fileinput文件上传组件使用详解
2017/06/06 Javascript
Vue.js做select下拉列表的实例(ul-li标签仿select标签)
2018/03/02 Javascript
微信小程序项目总结之点赞 删除列表 分享功能
2018/06/25 Javascript
详解webpack之图片引入-增强的file-loader:url-loader
2018/10/08 Javascript
vue中使用cookies和crypto-js实现记住密码和加密的方法
2018/10/18 Javascript
Node.js 多线程完全指南总结
2019/03/27 Javascript
基于mpvue小程序使用echarts画折线图的方法示例
2019/04/24 Javascript
微信小程序调用wx.getImageInfo遇到的坑解决
2020/05/31 Javascript
jQuery实现简单评论区功能
2020/10/26 jQuery
Python实现字符串的逆序 C++字符串逆序算法
2020/05/28 Python
Python学习小技巧总结
2018/06/10 Python
Python和Go语言的区别总结
2019/02/20 Python
VSCode Python开发环境配置的详细步骤
2019/02/22 Python
Python3之字节串bytes与字节数组bytearray的使用详解
2019/08/27 Python
Python实现点云投影到平面显示
2020/01/18 Python
浅谈Django中的QueryDict元素为数组的坑
2020/03/31 Python
简约控的天堂:The Undone
2016/12/21 全球购物
意大利火车票和铁路通行证专家:ItaliaRail
2019/01/22 全球购物
经济信息系毕业生自荐信范文
2014/03/15 职场文书
网络优化专员求职信
2014/05/04 职场文书
银行主办会计岗位职责
2014/08/13 职场文书
寒山寺导游词
2015/02/03 职场文书
因家庭原因离职的辞职信范文
2015/05/12 职场文书
首次购房证明
2015/06/19 职场文书
2016入党积极分子心得体会
2016/01/06 职场文书
德劲DE1107指针试高灵敏度全波段收音机机评
2022/04/05 无线电