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学习之流程控制实现代码
Jun 09 PHP
PHP include_path设置技巧分享
Jul 03 PHP
php var_export与var_dump 输出的不同
Aug 09 PHP
PHP对文件进行加锁、解锁实例
Jan 23 PHP
php实现网站顶踩功能的完整前端代码
Jul 19 PHP
PHP书写格式详解(必看)
May 23 PHP
PHP脚本自动识别验证码查询汽车违章
Dec 20 PHP
一键生成各种尺寸Icon的php脚本(实例)
Feb 08 PHP
实例讲解PHP中使用命名空间
Jan 27 PHP
PHP实现通过文本文件统计页面访问量功能示例
Feb 13 PHP
PHP7使用ODBC连接SQL Server2008 R2数据库示例【基于thinkPHP5.1框架】
May 06 PHP
解决Laravel5.5下的toArray问题
Oct 15 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
fleaphp下不确定的多条件查询的巧妙解决方法
2008/09/11 PHP
PHP开发不能违背的安全规则 过滤用户输入
2011/05/01 PHP
PHP在不同页面间传递Json数据示例代码
2013/06/08 PHP
js静态作用域的功能。
2006/12/25 Javascript
Javascript中eval函数的使用方法与示例
2007/04/09 Javascript
PNG背景在不同浏览器下的应用
2009/06/22 Javascript
Dojo 学习笔记入门篇 First Dojo Example
2009/11/15 Javascript
JS删除数组元素的函数介绍
2013/03/27 Javascript
jquery实现带二级菜单的导航示例
2014/04/28 Javascript
js四舍五入数学函数round使用实例
2014/05/09 Javascript
JS判断是否为JSON对象及是否存在某字段的方法(推荐)
2016/11/29 Javascript
Mac下使用charles遇到的问题以及解决办法
2017/01/10 Javascript
微信小程序 scroll-view隐藏滚动条详解
2017/01/16 Javascript
关于layui导航栏不展示下拉列表的解决方法
2019/09/25 Javascript
p5.js实现简单货车运动动画
2019/10/23 Javascript
[06:38]DOTA2怒掀电竞风暴 2013Chinajoy
2013/07/27 DOTA
[44:01]2018DOTA2亚洲邀请赛3月30日 小组赛B组 EG VS paiN
2018/03/31 DOTA
Python文件操作基本流程代码实例
2017/12/11 Python
一个简单的python爬虫程序 爬取豆瓣热度Top100以内的电影信息
2018/04/17 Python
python3基于TCP实现CS架构文件传输
2018/07/28 Python
selenium+python自动化测试之页面元素定位
2019/01/23 Python
使用python获取(宜宾市地震信息)地震信息
2019/06/20 Python
通过python实现弹窗广告拦截过程详解
2019/07/10 Python
python在openstreetmap地图上绘制路线图的实现
2019/07/11 Python
用Python爬取QQ音乐评论并制成词云图的实例
2019/08/24 Python
django的403/404/500错误自定义页面的配置方式
2020/05/21 Python
python实现图片转换成素描和漫画格式
2020/08/19 Python
纯CSS3实现地球自转实现代码(图文教程附送源码)
2012/12/26 HTML / CSS
html5唤醒APP小记
2019/03/27 HTML / CSS
韩国江南富人区高端时尚百货商场:Galleria(格乐丽雅)
2018/03/27 全球购物
业务经理岗位职责
2013/11/11 职场文书
小学语文教学反思
2014/02/10 职场文书
4s店市场专员岗位职责
2014/04/09 职场文书
小学数学新课改心得体会
2016/01/22 职场文书
python接口测试返回数据为字典取值方式
2022/02/12 Python
nginx配置指令之server_name的具体使用
2022/08/14 Servers