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的FTP学习(二)[转自奥索]
Oct 09 PHP
PHP 和 XML: 使用expat函数(一)
Oct 09 PHP
php设计模式 Strategy(策略模式)
Jun 26 PHP
php skymvc 一款轻量、简单的php
Jun 28 PHP
解析php开发中的中文编码问题
Aug 08 PHP
ThinkPHP结合ajax、Mysql实现的客户端通信功能代码示例
Jun 23 PHP
自己写的php curl库实现整站克隆功能
Feb 12 PHP
详解Window7 下开发php扩展
Dec 31 PHP
PHP使用Mysqli类库实现完美分页效果的方法
Apr 07 PHP
Thinkphp5行为使用方法汇总
Dec 21 PHP
php+ajax实现商品对比功能示例
Apr 13 PHP
php redis setnx分布式锁简单原理解析
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
使用 eAccelerator加速PHP代码的方法
2007/09/30 PHP
学习discuz php 引入文件的方法DISCUZ_ROOT
2009/06/21 PHP
ThinkPHP实现更新数据实例详解(demo)
2016/06/29 PHP
PHP Swoole异步读取、写入文件操作示例
2019/10/24 PHP
PHP 构造函数和析构函数原理与用法分析
2020/04/21 PHP
Javascript 浮点运算的问题分析与解决方法
2013/08/27 Javascript
jQuery DOM操作实例
2014/03/05 Javascript
javascript 事件处理示例分享
2014/12/31 Javascript
JavaScript函数详解
2015/02/27 Javascript
利用Plupload.js解决大文件上传问题, 带进度条和背景遮罩层
2017/03/15 Javascript
angularjs中的$eval方法详解
2017/04/24 Javascript
Javascript es7中比较实用的两个方法示例
2017/07/21 Javascript
详解Webstorm 新建.vue文件支持高亮vue语法和es6语法
2017/10/26 Javascript
Node.js 实现远程桌面监控的方法步骤
2019/07/02 Javascript
[16:27]DOTA2 HEROS教学视频教你分分钟做大人-艾欧
2014/06/11 DOTA
[01:15:12]DOTA2上海特级锦标赛主赛事日 - 1 败者组第一轮#4Newbee VS CDEC
2016/03/03 DOTA
简单的python协同过滤程序实例代码
2018/01/31 Python
python负载均衡的简单实现方法
2018/02/04 Python
在python中bool函数的取值方法
2018/11/01 Python
python定时按日期备份MySQL数据并压缩
2019/04/19 Python
解决python执行不输出系统命令弹框的问题
2019/06/24 Python
mac系统下Redis安装和使用步骤详解
2019/07/09 Python
python中时间转换datetime和pd.to_datetime详析
2019/08/11 Python
Python使用matplotlib 画矩形的三种方式分析
2019/10/31 Python
python实现指定ip端口扫描方式
2019/12/17 Python
Python使用pymysql模块操作mysql增删改查实例分析
2019/12/19 Python
python装饰器的特性原理详解
2019/12/25 Python
使用pickle存储数据dump 和 load实例讲解
2019/12/30 Python
Pycharm 2020.1 版配置优化的详细教程
2020/08/07 Python
css3学习系列之移动属性详解
2017/07/04 HTML / CSS
大学生应聘自荐信
2013/10/11 职场文书
2015银行年终工作总结范文
2015/05/26 职场文书
摩登时代观后感
2015/06/03 职场文书
歼十出击观后感
2015/06/11 职场文书
安全知识竞赛主持词
2015/06/30 职场文书
PyCharm 配置SSH和SFTP连接远程服务器
2022/05/11 Python