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 file_exists 检查文件或目录是否存在的函数
May 10 PHP
深入php处理整数函数的详解
Jun 09 PHP
PHP session_start()问题解疑(详细介绍)
Jul 05 PHP
奉献出一个封装的curl函数 便于调用(抓数据专用)
Jul 22 PHP
百度ping方法使用示例 自动ping百度
Jan 26 PHP
ThinkPHP模板自定义标签使用方法
Jun 26 PHP
PHP加密解密类实例分析
Apr 20 PHP
php删除文本文件中重复行的方法
Apr 28 PHP
php简单判断文本编码的方法
Jul 30 PHP
Linux系统中设置多版本PHP共存配合Nginx服务器使用
Dec 21 PHP
Yii2搭建后台并实现rbac权限控制完整实例教程
Apr 28 PHP
Yii配置与使用memcached缓存的方法
Jul 13 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 小乘法表实现代码
2009/07/16 PHP
js加解密 脚本解密
2008/02/22 Javascript
JavaScript中常用的运算符小结
2012/01/18 Javascript
JQuery入门——事件切换之hover()方法应用介绍
2013/02/05 Javascript
JavaScript二维数组实现的省市联动菜单
2014/05/08 Javascript
node.js中的fs.chmodSync方法使用说明
2014/12/18 Javascript
详细解读JavaScript编程中的Promise使用
2015/07/27 Javascript
JS实现仿QQ效果的三级竖向菜单
2015/09/25 Javascript
使用jQuery5分钟快速搞定双色表格的简单实例
2016/08/08 Javascript
JS中位置与大小的获取方法
2016/11/22 Javascript
正则表达式基本语法及表单验证操作详解【基于JS】
2017/04/07 Javascript
JS去掉字符串中所有的逗号
2017/10/18 Javascript
Vue2.0点击切换类名改变样式的方法
2018/08/22 Javascript
微信小程序mpvue点击按钮获取button值的方法
2019/05/29 Javascript
vue 解决文本框被键盘遮住的问题
2019/11/06 Javascript
如何使用webpack打包一个库library的方法步骤
2019/12/18 Javascript
Vue组件基础用法详解
2020/02/05 Javascript
详解vue中v-model和v-bind绑定数据的异同
2020/08/10 Javascript
详解ES6实现类的私有变量的几种写法
2021/02/10 Javascript
python中文编码问题小结
2014/09/28 Python
Python3将数据保存为txt文件的方法
2019/09/12 Python
pytorch 修改预训练model实例
2020/01/18 Python
python实现简单的购物程序代码实例
2020/03/03 Python
C++和python实现阿姆斯特朗数字查找实例代码
2020/12/07 Python
美国肌肉和力量商店:Muscle & Strength
2019/06/22 全球购物
综合测评自我鉴定
2013/10/08 职场文书
出纳岗位职责模板
2013/11/27 职场文书
应届实习生的自我评价范文
2014/01/05 职场文书
机电一体化职业规划书
2014/01/07 职场文书
村党支部公开承诺书
2014/05/29 职场文书
2015年秋季运动会加油稿
2015/07/22 职场文书
幼儿园教师管理制度
2015/08/05 职场文书
2016年“抗战胜利纪念日”71周年校园广播稿
2015/12/18 职场文书
公务员学习中国梦心得体会
2016/01/05 职场文书
Python实现批量自动整理文件
2022/03/16 Python
nginx.conf配置文件结构小结
2022/04/08 Servers