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 相关文章推荐
PHP4引用文件语句的对比
Oct 09 PHP
如何获知PHP程序占用多少内存(memory_get_usage)
Sep 23 PHP
PHP基础知识介绍
Sep 17 PHP
discuz加密解密函数使用方法和中文注释
Jan 21 PHP
phpmailer发送邮件之后,返回收件人是否阅读了邮件的方法
Jul 19 PHP
ThinkPHP中的三大自动简介
Aug 22 PHP
php+mysqli事务控制实现银行转账实例
Jan 29 PHP
支付宝服务窗API接口开发php版本
Jul 20 PHP
PHP页面输出时js设置input框的选中值
Sep 30 PHP
PHP链表操作简单示例
Oct 15 PHP
PHP实现图片批量打包下载功能
Mar 01 PHP
关于laravel框架中的常用目录路径函数
Oct 23 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/02 无线电
Win9x/ME下Apache+PHP安装配置
2006/10/09 PHP
怎样在PHP中通过ADO调用Asscess数据库和COM程序
2006/10/09 PHP
php根据年月获取季度的方法
2014/03/31 PHP
Thinkphp将二维数组变为标签适用的一维数组方法总结
2014/10/30 PHP
PHP基于CURL进行POST数据上传实例
2014/11/10 PHP
php连接oracle数据库及查询数据的方法
2014/12/29 PHP
php生成mysql的数据字典
2016/07/07 PHP
laravel admin实现分类树/模型树的示例代码
2020/06/10 PHP
JavaScript修改css样式style
2008/04/15 Javascript
Javascript学习笔记1 数据类型
2010/01/11 Javascript
jQuery实现表头固定效果的实例代码
2013/05/24 Javascript
纯JavaScript实现HTML5 Canvas六种特效滤镜示例
2013/06/28 Javascript
Javascript中浮点数相乘的一个解决方法
2014/06/03 Javascript
node.js中使用q.js实现api的promise化
2014/09/17 Javascript
自定义刻度jQuery进度条及插件
2015/09/02 Javascript
JS实现左右拖动改变内容显示区域大小的方法
2015/10/13 Javascript
JS在Chrome浏览器中showModalDialog函数返回值为undefined的解决方法
2016/08/03 Javascript
javascript实现无法关闭的弹框
2016/11/27 Javascript
JS Input里添加小图标的两种方法
2017/11/11 Javascript
C#实现将一个字符转换为整数
2017/12/12 Javascript
解决Jquery下拉框数据动态获取的问题
2018/01/25 jQuery
vue引入js数字小键盘的实现代码
2018/05/14 Javascript
详解js 创建对象的几种方法
2019/03/08 Javascript
VUE table表格动态添加一列数据,新增的这些数据不可以编辑(v-model绑定的数据不能实时更新)
2020/04/03 Javascript
Vue路由的模块自动化与统一加载实现
2020/06/05 Javascript
python正则表达式match和search用法实例
2015/03/26 Python
python画一个玫瑰和一个爱心
2020/08/18 Python
12个步骤教你理解Python装饰器
2019/07/01 Python
Python八皇后问题解答过程详解
2019/07/29 Python
Python结合Window计划任务监测邮件的示例代码
2020/08/05 Python
总结python 三种常见的内存泄漏场景
2020/11/20 Python
详解HTML5 window.postMessage与跨域
2017/05/11 HTML / CSS
计算机应用毕业生自荐信
2013/10/23 职场文书
篮球赛闭幕式主持词
2015/07/03 职场文书
党性教育心得体会(共6篇)
2016/01/21 职场文书