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 相关文章推荐
一个简单的自动发送邮件系统(一)
Oct 09 PHP
PHP 文件上传进度条的两种实现方法的代码
Nov 25 PHP
apache2.2.4+mysql5.0.77+php5.2.8安装精简
Apr 29 PHP
PHP5.2中date()函数显示时间与北京时间相差8小时的解决办法
May 28 PHP
PHP 木马攻击防御技巧
Jun 13 PHP
mysql,mysqli,PDO的各自不同介绍
Sep 19 PHP
php检测图片木马多进制编程实践
Apr 11 PHP
php ZipArchive压缩函数详解实例
Nov 06 PHP
Smarty中常用变量操作符汇总
Oct 27 PHP
php中switch与ifelse的效率区别及适用情况分析
Feb 12 PHP
php中文字符串截取多种方法汇总
Oct 06 PHP
利用Laravel事件系统如何实现登录日志的记录详解
May 20 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笔记之:php函数range() round()和list()的使用说明
2013/04/26 PHP
PHP微信开发之根据用户回复关键词\位置返回附近信息
2016/06/24 PHP
php生成word并下载代码实例
2019/03/15 PHP
Javascript 的addEventListener()及attachEvent()区别分析
2009/05/21 Javascript
用jQuery扩展自写的 UI导航
2010/01/13 Javascript
基于jQuery实现带动画效果超炫酷的弹出对话框(附源码下载)
2016/02/22 Javascript
使用BootStrap实现用户登录界面UI
2016/08/10 Javascript
js 获取html5的data属性实现方法
2017/07/28 Javascript
vue axios 二次封装的示例代码
2017/12/08 Javascript
JS简单实现动态添加HTML标记的方法示例
2018/04/08 Javascript
微信小程序实现倒计时调用相机自动拍照功能
2018/06/10 Javascript
详解vue移动端项目代码拆分记录
2019/03/15 Javascript
js中数组常用方法总结(推荐)
2019/04/09 Javascript
详解微信UnionID作用
2019/05/15 Javascript
浅谈layer弹出层按钮颜色修改方法
2019/09/11 Javascript
js 使用ajax设置和获取自定义header信息的方法小结
2020/03/12 Javascript
使用Angular9和TypeScript开发RPG游戏的方法
2020/03/25 Javascript
JQuery实现折叠式菜单的详细代码
2020/06/03 jQuery
Python+Socket实现基于TCP协议的客户与服务端中文自动回复聊天功能示例
2017/08/31 Python
小白如何入门Python? 制作一个网站为例
2018/03/06 Python
Python扩展内置类型详解
2018/03/26 Python
Python第三方库face_recognition在windows上的安装过程
2019/05/03 Python
网易有道2017内推编程题 洗牌(python)
2019/06/19 Python
python matplotlib包图像配色方案分享
2020/03/14 Python
如何理解Python中包的引入
2020/05/29 Python
Python Dict找出value大于某值或key大于某值的所有项方式
2020/06/05 Python
Python lambda表达式原理及用法解析
2020/08/18 Python
Lands’ End官网:经典的美国生活方式品牌
2016/08/14 全球购物
SkinCeuticals官网:美国药妆品牌
2018/04/19 全球购物
最新销售员个人自荐信
2013/09/21 职场文书
汽车检测与维修个人求职信
2013/09/24 职场文书
公司市场部岗位职责
2013/12/02 职场文书
领导干部培训感言
2014/01/23 职场文书
python爬取网页版QQ空间,生成各类图表
2021/06/02 Python
MySQL8.0升级的踩坑历险记
2021/11/01 MySQL
详解Vue中$props、$attrs和$listeners的使用方法
2022/02/18 Vue.js