This article analyzes the Zend Framework routing mechanism code. Share it with everyone for your reference, the details are as follows:
In the framework, the calling relationship of routing is:
1. Apache’s mod_rewrite module routes requests to the framework’s startup script, usually index.php;
2. The front-end controller Zend_Controller_Front distributes requests through the dispatch function;
3. The router Zend_Controller_Router_Rewrite processes routing through the route function. For the existing routing rules in the router, the match function is called on each route in the reverse order of the adding order (similar to a stack, last in first out) to check whether the request is consistent with the current one. The routing rules match. If they match, set the router's current route variable ($_currentRoute) to the matching route, and pass the parameters parsed by route to the Zend_Controller_Request_Http object. Complete the route setting here.
If no route is found, the framework will use the index action of the Index controller.
Analysis of function code in Zend_Controller_Router_Route:
1. Constructor
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. Matching algorithm
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; }
Readers who are interested in more zend-related content can check out the special topics of this site: "Zend FrameWork Framework Introductory Tutorial", "php Excellent Development Framework Summary", "Yii Framework Introduction and Summary of Common Techniques", "ThinkPHP Introductory Tutorial" , "php object-oriented programming introductory tutorial", "php mysql database operation introductory tutorial" and "php common database operation skills summary"
I hope this article will be helpful to everyone’s PHP programming based on the Zend Framework framework.