Zend Framework框架路由机制代码分析


Posted in PHP onMarch 22, 2016

本文分析了Zend Framework框架路由机制代码。分享给大家供大家参考,具体如下:

在框架中,有关路由的调用关系为:

1、apache的mod_rewrite模块把请求路由到框架的启动脚本,一般是index.php;

2、前端控制器Zend_Controller_Front通过dispatch函数进行请求分发;

3、路由器Zend_Controller_Router_Rewrite通过route函数处理路由,对路由器中已有的路由规则,按照加入顺序的逆序(类似于栈,后进先出)对每个route调用match函数,以检查请求是否和当前路由规则匹配,如果匹配的话把路由器的当前路由这个变量($_currentRoute)设置为匹配的路由,并把route解析出来的参数传给Zend_Controller_Request_Http对象,到这里完成路由设置。

如果没有发现路由,框架会使用Index控制器的index这个action。

对Zend_Controller_Router_Route中的函数代码分析:

1、构造函数

public function __construct($route, $defaults = array(), $reqs = array())
{
  $route = trim($route, $this->_urlDelimiter); //去掉规则首尾的url分隔符(默认是/)
  $this->_defaults = (array) $defaults; //默认值数组,以变量名为键
  $this->_requirements = (array) $reqs; //变量需要满足的正则表达式,以变量名为键
  if ($route != '') {
   foreach (explode($this->_urlDelimiter, $route) as $pos => $part) {
    //把规则切分为一个数组
    if (substr($part, 0, 1) == $this->_urlVariable) {//如果是一个变量的定义
     $name = substr($part, 1); //获取变量名
     //如果该变量定义了对应的正则表达式,则获取该表达式,否则置为null
     $regex = (isset($reqs[$name]) ? $reqs[$name] : $this->_defaultRegex);
     //_parts数组包含了规则的各个部分,如果是变量的话,数组中有name元素
     $this->_parts[$pos] = array('name' => $name, 'regex' => $regex);
     //_vars包含了该规则中的所有变量的名字
     $this->_vars[] = $name;
    } else { //普通字符串
     $this->_parts[$pos] = array('regex' => $part);
     if ($part != '*') {
      $this->_staticCount++; //该规则的普通字符串的个数
     }
    }
   }
  }
}

2、匹配算法

public function match($path)
{
  $pathStaticCount = 0;
  $defaults = $this->_defaults; //默认值数组,数组元素的键值是变量名
   //默认值数组的一个拷贝,不过变量的值全部换成布尔值,其实这个值并没有实际用处,下面程序仅仅
  //是通过判断键值是否存在而确定是否包含一个变量,可能这么做是为了节省空间,不过要是这样的话
  //不如直接使用 $this->_defaults了?
  if (count($defaults)) {
   $unique = array_combine(array_keys($defaults), array_fill(0, count($defaults), true));
  } else {
   $unique = array();
  }
  $path = trim($path, $this->_urlDelimiter); //传入的path是已经去掉baseUrl的,这里确保去掉首尾的分隔符
  if ($path != '') {
   $path = explode($this->_urlDelimiter, $path);
   foreach ($path as $pos => $pathPart) {
    if (!isset($this->_parts[$pos])) {
     //把path根据url分隔符分割为数组后,把每一部分和规则的对应部分比较,如果path中存在,
     //而规则中不存在对应部分,那么该规则肯定不匹配,这里要注意$pos,是通过它把规则
     //和path的对应部分对应起来。
     return false;
    }
    if ($this->_parts[$pos]['regex'] == '*') {
      //如果规则的当前部分是通配符*,则把path的剩余部分解释为url传递过来的变量,他们按照
     //“变量名/变量值”这样的形式成对出现
     $parts = array_slice($path, $pos); //获取path的剩余部分
     $this->_getWildcardData($parts, $unique);
     break;
    }
    $part = $this->_parts[$pos];
    $name = isset($part['name']) ? $part['name'] : null;
    $pathPart = urldecode($pathPart);//对传过来的值进行解码
    if ($name === null) {//普通字符串,和规则的对应部分比较是否相等即可
     if ($part['regex'] != $pathPart) {
      return false;
     }
    } elseif ($part['regex'] === null) {
      //如果是变量,但是没有需要满足的正则表达式,那么只有值不为空就可以了
     if (strlen($pathPart) == 0) {
      return false;
     }
    } else {//如果对该变量需要满足一个正则表达式,那么这里进行验证
     $regex = $this->_regexDelimiter . '^' . $part['regex'] . '$' . $this->_regexDelimiter . 'iu';
     if (!preg_match($regex, $pathPart)) {
      return false;
     }
    }
    if ($name !== null) {
     // 如果是一个变量,则设置变量的值
     $this->_values[$name] = $pathPart;
     $unique[$name] = true; //其实没有必要设置,这个版本根本就没有用它
    } else {
     //把普通字符串的匹配计数加1,因为规则中的普通字符串是必须在path中存在的,否则就是
     //匹配失败
     $pathStaticCount++;
    }
   }
  }
   //$this->_values中保存的是分析获取的变量,如果规则中存在‘*',则$this->_params是获取的
  //变量,否则是空数组,$this->_defaults是规则提供的默认变量值,这里用‘+'把三个数组相加
  //这样的好处是如果后面的数组与前面的数组有相同的非整数的键值,后面的不会覆盖前面的,这
  //与array_merge函数有区别,后者是会覆盖的。也就是说,如果$this->_values 中已经有键controller
  //,那么$this->_defaults中的controller元素就被忽略,这样就$this->_defaults中的默认值只有在path
  //中不存在的时候才会出现在返回值中。
  $return = $this->_values + $this->_params + $this->_defaults;
  // Check if all static mappings have been met
  if ($this->_staticCount != $pathStaticCount) {//规则的所有普通字符串必须在path中得到匹配
   return false;
  }
  // 解析完后,规则定义的所有变量也必须全部出现,否则视为不匹配
  foreach ($this->_vars as $var) {
   if (!array_key_exists($var, $return)) {
    return false;
   }
  }
  return $return;
}

希望本文所述对大家基于Zend Framework框架的PHP程序设计有所帮助。

PHP 相关文章推荐
PHP中在数据库中保存Checkbox数据(2)
Oct 09 PHP
一个没有MYSQL数据库支持的简易留言本的编写
Oct 09 PHP
优化使用mysql存储session的php代码
Jan 10 PHP
PHP 文件上传功能实现代码
Jun 24 PHP
支持中文的php加密解密类代码
Nov 27 PHP
国外PHP程序员的13个好习惯小结
Feb 20 PHP
解析PHP无限级分类方法及代码
Jun 21 PHP
提高PHP性能的编码技巧以及性能优化详细解析
Aug 24 PHP
PHP基于数组实现的分页函数实例
Aug 20 PHP
解决nginx不支持thinkphp中pathinfo的问题
Jul 21 PHP
ThinkPHP中数据操作案例分析
Sep 27 PHP
php自定义函数实现二维数组排序功能
Jul 20 PHP
PHP实现补齐关闭的HTML标签
Mar 22 #PHP
Zend Framework实现留言本分页功能(附demo源码下载)
Mar 22 #PHP
Zend Framework实现具有基本功能的留言本(附demo源码下载)
Mar 22 #PHP
Zend Framework实现将session存储在memcache中的方法
Mar 22 #PHP
Zend Framework分页类用法详解
Mar 22 #PHP
Zend Framework生成验证码并实现验证码验证功能(附demo源码下载)
Mar 22 #PHP
PHP的Laravel框架中使用AdminLTE模板来编写网站后台界面
Mar 21 #PHP
You might like
windows xp下安装pear
2006/12/02 PHP
ThinkPHP令牌验证实例
2014/06/18 PHP
跟我学Laravel之请求与输入
2014/10/15 PHP
JavaScript CSS修改学习第五章 给“上传”添加样式
2010/02/19 Javascript
JavaScript 盒模型 尺寸深入理解
2012/12/31 Javascript
js判断子窗体是否关闭的方法
2015/08/11 Javascript
基于JS判断iframe是否加载成功的方法(多种浏览器)
2016/05/13 Javascript
jQuery实现鼠标经过购物车出现下拉框代码(推荐)
2016/07/21 Javascript
简单的JS控制button颜色随点击更改的实现方法
2017/04/17 Javascript
详解Vue-cli 创建的项目如何跨域请求
2017/05/18 Javascript
Vue组件之单向数据流的解决方法
2018/11/10 Javascript
从零开始在NPM上发布一个Vue组件的方法步骤
2018/12/20 Javascript
echarts大屏字体自适应的方法步骤
2019/07/12 Javascript
Vue 利用指令实现禁止反复发送请求的两种方法
2019/09/15 Javascript
原生JS无缝滑动轮播图
2019/10/22 Javascript
JS 获取文件后缀,判断文件类型(比如是否为图片格式)
2020/05/09 Javascript
vue 组件间的通信之子组件向父组件传值的方式
2020/07/29 Javascript
Nest.js 授权验证的方法示例
2021/02/22 Javascript
[02:07]DOTA2超级联赛专访BBC:难忘网吧超神经历
2013/06/09 DOTA
python通过正则查找微博@(at)用户的方法
2015/03/13 Python
python文件特定行插入和替换实例详解
2017/07/12 Python
matplotlib subplots 调整子图间矩的实例
2018/05/25 Python
Django 全局的static和templates的使用详解
2019/07/19 Python
Python+OpenCv制作证件图片生成器的操作方法
2019/08/21 Python
python opencv 图像边框(填充)添加及图像混合的实现方法(末尾实现类似幻灯片渐变的效果)
2020/03/09 Python
Django-rest-framework中过滤器的定制实例
2020/04/01 Python
使用html2canvas.js实现页面截图并显示或上传的示例代码
2018/12/18 HTML / CSS
日本最大美瞳直送网:Morecontact(中文)
2019/04/03 全球购物
儿科主治医生个人求职信
2013/09/23 职场文书
新闻编辑自荐信
2013/11/03 职场文书
软件售后服务承诺书
2014/05/21 职场文书
公务员爱岗敬业演讲稿
2014/08/26 职场文书
2015年班级元旦晚会活动总结
2014/11/28 职场文书
私人贷款担保书该怎么写呢?
2019/07/02 职场文书
MySQL中的布尔值,怎么存储false或true
2021/06/04 MySQL
微软PC Health Check电脑健康状况检查应用下载(Win11配置检测工具)
2021/06/26 数码科技