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 xml-rpc远程调用
Dec 19 PHP
ThinkPHP自动验证失败的解决方法
Jun 09 PHP
使用PHP实现密保卡功能实现代码<打包下载直接运行>
Oct 09 PHP
解析PHP中的内存管理,PHP动态分配和释放内存
Jun 28 PHP
php修改NetBeans默认字体的大小
Jul 02 PHP
php使用cookie显示用户上次访问网站日期的方法
Jan 26 PHP
php获取网页上所有链接的方法
Apr 03 PHP
Codeigniter的dom类用法实例
Jun 26 PHP
PHP设置进度条的方法
Jul 08 PHP
PHP制作用户注册系统
Oct 23 PHP
PHP使用Session实现上传进度功能详解
Aug 06 PHP
基于ThinkPHP删除目录及目录文件函数
Oct 28 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 解决旧系统 查出所有数据分页的类
2012/08/27 PHP
win7安装php框架Yii的方法
2016/01/25 PHP
发布一个高效的JavaScript分析、压缩工具 JavaScript Analyser
2007/11/30 Javascript
获取焦点时,利用js定时器设定时间执行动作
2010/04/02 Javascript
THREE.JS入门教程(6)创建自己的全景图实现步骤
2013/01/25 Javascript
自己封装的javascript事件队列函数版
2014/06/12 Javascript
简单实现兼容各大浏览器的js复制内容到剪切板
2015/09/09 Javascript
javascript实现网页端解压并查看zip文件
2015/12/15 Javascript
JavaScript File API实现文件上传预览
2016/02/02 Javascript
js实现产品缩略图效果
2017/03/10 Javascript
vue调用高德地图实例代码
2017/04/28 Javascript
Vue之Watcher源码解析(1)
2017/07/19 Javascript
nodejs基于WS模块实现WebSocket聊天功能的方法
2018/01/12 NodeJs
webpack v4 从dev到prd的方法
2018/04/02 Javascript
js中怎么判断两个字符串相等的实例
2019/01/17 Javascript
详解django模板与vue.js冲突问题
2019/07/07 Javascript
python 2.6.6升级到python 2.7.x版本的方法
2016/10/09 Python
Python3使用PyQt5制作简单的画板/手写板实例
2017/10/19 Python
Python中的上下文管理器和with语句的使用
2018/04/17 Python
pycharm恢复默认设置或者是替换pycharm的解释器实例
2018/10/29 Python
Python DataFrame一列拆成多列以及一行拆成多行
2019/08/06 Python
Python操作MySQL数据库的示例代码
2020/07/13 Python
Html5 滚动穿透的方法
2019/05/13 HTML / CSS
澳大利亚网上书店:QBD
2021/01/09 全球购物
留学推荐信写作指南
2014/01/25 职场文书
施工材料员岗位职责
2014/02/12 职场文书
创意婚礼策划方案
2014/05/18 职场文书
个人债务授权委托书范本
2014/10/05 职场文书
世界水日宣传活动总结
2015/02/09 职场文书
八月一日观后感
2015/06/10 职场文书
有关朝花夕拾的读书笔记
2015/06/29 职场文书
2015年“我们的节日·中秋节”活动总结
2015/07/30 职场文书
2016年习总书记讲话学习心得体会
2016/01/20 职场文书
迎客户欢迎词三篇
2019/09/27 职场文书
python基础入门之字典和集合
2021/06/13 Python
Python连接Postgres/Mysql/Mongo数据库基本操作大全
2021/06/29 Python