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原创论坛
Oct 09 PHP
全文搜索和替换
Oct 09 PHP
PHP中函数内引用全局变量的方法
Oct 20 PHP
PHP教程 基本语法
Oct 23 PHP
php调用新浪短链接API的方法
Nov 08 PHP
php模拟登陆的实现方法分析
Jan 09 PHP
PHP模拟asp.net的StringBuilder类实现方法
Aug 08 PHP
php实现购物车功能(上)
Jul 23 PHP
PHP输出图像imagegif、imagejpeg与imagepng函数用法分析
Nov 14 PHP
解决Laravel blade模板转义html标签的问题
Sep 03 PHP
PHP实现基本留言板功能原理与步骤详解
Mar 26 PHP
2020最新版 PhpStudy V8.1版本下载安装使用详解
Oct 30 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
法国:浪漫之都的咖啡文化
2021/03/03 咖啡文化
通过php删除xml文档内容的方法
2015/01/23 PHP
PHP文件生成的图片无法使用CDN缓存的解决方法
2015/06/20 PHP
PHP+iframe图片上传实现即时刷新效果
2016/11/18 PHP
JavaScript 5 新增 Array 方法实现介绍
2012/02/06 Javascript
使用jquery实现仿百度自动补全特效
2015/07/23 Javascript
jQuery点击按钮弹出遮罩层且内容居中特效
2015/12/14 Javascript
禁用backspace网页回退功能的实现代码
2016/11/15 Javascript
JS实现网页抢购功能(触发,终止脚本)
2017/11/27 Javascript
详解vue渲染函数render的使用
2017/12/12 Javascript
vue2.0 中使用transition实现动画效果使用心得
2018/08/13 Javascript
简述vue-cli中chainWebpack的使用方法
2019/07/30 Javascript
vue 实现路由跳转时更改页面title
2019/11/05 Javascript
[02:33]2018 DOTA2亚洲邀请赛回顾视频 再次拾起那些美妙的时刻
2018/04/10 DOTA
详解Python中表达式i += x与i = i + x是否等价
2017/02/08 Python
Python实现的购物车功能示例
2018/02/11 Python
Python 循环终止语句的三种方法小结
2019/06/24 Python
解决django服务器重启端口被占用的问题
2019/07/26 Python
扩展Django admin的list_filter()可使用范围方法
2019/08/21 Python
Python3 使用map()批量的转换数据类型,如str转float的实现
2019/11/29 Python
python pillow库的基础使用教程
2021/01/13 Python
使用css3实现的tab选项卡代码分享
2014/12/09 HTML / CSS
市场营销专业毕业生自荐信
2013/11/02 职场文书
大学生家政服务项目创业计划书
2014/01/30 职场文书
个人公开承诺书
2014/03/28 职场文书
学校爱心捐款倡议书
2014/05/13 职场文书
原料仓仓管员岗位职责
2014/07/08 职场文书
学生吸烟检讨书
2014/09/14 职场文书
党的群众路线教育实践活动个人整改措施
2014/10/27 职场文书
高校教师个人工作总结2014
2014/12/17 职场文书
新兵入伍决心书
2015/09/22 职场文书
会计专业自荐信范文
2019/05/22 职场文书
在前女友婚礼上,用Python破解了现场的WIFI还把名称改成了
2021/05/28 Python
详解Python生成器和基于生成器的协程
2021/06/03 Python
使用Oracle命令进行数据库备份与还原
2021/12/06 Oracle
教你nginx跳转配置的四种方式
2022/07/07 Servers