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 相关文章推荐
example1.php
Oct 09 PHP
PHP 动态随机生成验证码类代码
Apr 09 PHP
php array_search() 函数使用
Apr 13 PHP
兼容firefox,chrome的网页灰度效果
Aug 08 PHP
解析PHP计算页面执行时间的实现代码
Jun 18 PHP
解析argc argv在php中的应用
Jun 24 PHP
php递归获取目录内文件(包含子目录)封装类分享
Dec 25 PHP
PHP的foreach中使用引用时需要注意的一个问题和解决方法
May 29 PHP
四个常见html网页乱码问题及解决办法
Sep 08 PHP
PHP微信开发之微信消息自动回复下所遇到的坑
May 09 PHP
PHP格式化显示时间date()函数代码
Oct 03 PHP
PHP date_default_timezone_set()设置时区操作实例分析
May 16 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
默默简单的写了一个模板引擎
2007/01/02 PHP
一步一步学习PHP(3) php 函数
2010/02/15 PHP
php读取文件内容到数组的方法
2015/03/16 PHP
PHP限制HTML内容中图片必须是本站的方法
2015/06/16 PHP
深入理解PHP类的自动载入机制
2016/09/16 PHP
css3实现背景模糊的三种方式
2021/03/09 HTML / CSS
一个js写的日历(代码部分网摘)
2009/09/20 Javascript
Whatever:hover 无需javascript让IE支持丰富伪类
2010/06/29 Javascript
用JS判别浏览器种类以及IE版本的几种方法小结
2011/08/02 Javascript
浏览器解析js生成的html出现样式问题的解决方法
2012/04/16 Javascript
Jquery使用css方法改变样式实例
2015/05/18 Javascript
第九篇Bootstrap导航菜单创建步骤详解
2016/06/21 Javascript
基于jQuery实现歌词滚动版音乐播放器的代码
2016/09/17 Javascript
js获取当前时间(昨天、今天、明天)
2016/11/23 Javascript
js 转义字符及URI编码详解
2017/02/28 Javascript
JavaScript关联数组用法分析【概念、定义、遍历】
2017/03/15 Javascript
AngularJS动态绑定ng-options的ng-model实例代码
2017/06/21 Javascript
Javascript中parseInt的正确使用方式
2018/10/17 Javascript
vuex+axios+element-ui实现页面请求loading操作示例
2020/02/02 Javascript
vue addRoutes路由动态加载操作
2020/08/04 Javascript
python根据京东商品url获取产品价格
2015/08/09 Python
python实现字符串连接的三种方法及其效率、适用场景详解
2017/01/13 Python
Python分析学校四六级过关情况
2017/11/22 Python
对python numpy数组中冒号的使用方法详解
2018/04/17 Python
NumPy 数学函数及代数运算的实现代码
2018/07/18 Python
Python爬虫使用代理IP的实现
2019/10/27 Python
python 实现一个反向单位矩阵示例
2019/11/29 Python
关于python3.7安装matplotlib始终无法成功的问题的解决
2020/07/28 Python
localStorage 设置过期时间的方法实现
2018/12/21 HTML / CSS
Burt’s Bees英国官网:世界领先的天然个人护理品牌
2020/08/17 全球购物
一份Java笔试题
2012/02/21 面试题
请写出char *p与"零值"比较的if语句
2014/09/24 面试题
建筑安全生产目标责任书
2014/07/23 职场文书
竞聘自述材料
2014/08/25 职场文书
2014年护士长工作总结
2014/11/11 职场文书
2015年暑期社会实践总结
2015/07/13 职场文书