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 相关文章推荐
建立文件交换功能的脚本(二)
Oct 09 PHP
我的论坛源代码(四)
Oct 09 PHP
配置支持SSI
Nov 25 PHP
phpMyAdmin 链接表的附加功能尚未激活的问题
Aug 01 PHP
php中的三元运算符使用说明
Jul 03 PHP
linux命令之调试工具strace的深入分析
Jun 03 PHP
PHP网页游戏学习之Xnova(ogame)源码解读(十四)
Jun 26 PHP
详解PHP中的状态模式编程
Aug 11 PHP
解决Yii2邮件发送结果返回成功,但接收不到邮件的问题
May 23 PHP
PHP实现的折半查找算法示例
Dec 19 PHP
PHP实现微信对账单处理
Oct 01 PHP
Yii框架where查询用法实例分析
Oct 22 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 isset()与empty()的使用区别详解
2010/08/29 PHP
PHP原生函数一定好吗?
2014/12/08 PHP
PHP连接SQLServer2005的方法
2015/01/27 PHP
PHP遍历数组的三种方法及效率对比分析
2015/02/12 PHP
php获取网站百度快照日期的方法
2015/07/29 PHP
thinkPHP中session()方法用法详解
2016/12/08 PHP
php实现的生成迷宫与迷宫寻址算法完整实例
2017/11/06 PHP
PHP中一个有趣的preg_replace函数详解
2018/08/15 PHP
window.js 主要包含了页面的一些操作
2009/12/23 Javascript
jQuery 选择器详解
2015/01/19 Javascript
JavaScript使用concat连接数组的方法
2015/04/06 Javascript
js完美解决IE6不支持position:fixed的bug
2015/04/24 Javascript
javascript检测两个数组是否相似
2015/05/19 Javascript
Bootstrap中glyphicons-halflings-regular.woff字体报404错notfound的解决方法
2017/01/19 Javascript
jquery滚动条插件slimScroll使用方法
2017/02/09 Javascript
JS打开摄像头并截图上传示例
2017/02/18 Javascript
给Easyui-Datebox设置隐藏或者不可用的解决方法
2017/05/26 Javascript
微信小程序实现点击返回顶层的方法
2017/07/12 Javascript
node文件批量重命名的方法示例
2017/10/23 Javascript
微信小程序使用gitee进行版本管理
2018/09/20 Javascript
python sort、sorted高级排序技巧
2014/11/21 Python
Python实现的飞速中文网小说下载脚本
2015/04/23 Python
对Python正则匹配IP、Url、Mail的方法详解
2018/12/25 Python
如何安装并使用conda指令管理python环境
2019/07/10 Python
python实现12306登录并保存cookie的方法示例
2019/12/17 Python
pycharm通过anaconda安装pyqt5的教程
2020/03/24 Python
使用python把xmind转换成excel测试用例的实现代码
2020/10/12 Python
CSS3的Border-radius轻松制作圆角
2012/12/24 HTML / CSS
C# Debug和Testing相关面试题
2015/10/25 面试题
企业消防安全制度
2014/02/02 职场文书
先进人物事迹材料
2014/12/29 职场文书
三傻大闹宝莱坞观后感
2015/06/03 职场文书
《打电话》教学反思
2016/02/22 职场文书
廉政党课工作报告案例
2019/06/21 职场文书
导游词之阆中古城
2019/12/23 职场文书
Python数据分析之pandas函数详解
2021/04/21 Python