array( * 'instance' => (Route), * 'rules' => array( * (string) $rewrite_pattern => (array) $rule, * ... , * ), * 'reverse_rules' => array( * (string)$fingerprint => (string)$rewrite_pattern, * ... , * ), * ), * ); */ static private $structs; protected $struct; # 禁止被外部new private function __construct($route_file) { if (!file_exists($route_file) || !is_file($route_file)) { $route_rules = array(); } else { $route_rules = include($route_file); } $rules = array(); $reverse_rules = array(); if (!$route_rules || !is_array($route_rules)) { self::$structs[$route_file]['rules'] = $rules; self::$structs[$route_file]['reverse_rules'] = $reverse_rules; return; } foreach ($route_rules as $rewrite_pattern => $rule) { if (!isset($rule['a']) || !$rule['a']) { $rule['a'] = 'default'; } $fingerprint = $this->generateFingerprint($rule); $rules[$rewrite_pattern] = $rule; $reverse_rules[$fingerprint] = $rewrite_pattern; } self::$structs[$route_file]['rules'] = $rules; self::$structs[$route_file]['reverse_rules'] = $reverse_rules; } /** * * 生成指纹,方便反向rewrite时高效查找。 * @param array $args * @return string */ private function generateFingerprint($args) { if (!isset($args['a'])) { $args['a'] = 'default'; } $arg_eles = array_combine(array_keys($args), array_fill(0, count($args), null)); if (isset($args['a'])) $arg_eles['a'] = $args['a']; if (isset($args['c'])) $arg_eles['c'] = $args['c']; ksort($arg_eles); return Math::md5_16(print_r($arg_eles, true)); } /** * * @return KIF\Route */ static public function getInstance() { $route_file = Config::getInstance()->get('route_file'); $route_file = realpath($route_file); if (!isset(self::$structs[$route_file])) { self::$structs[$route_file]['instance'] = new self($route_file); } self::$structs[$route_file]['instance']->struct = & self::$structs[$route_file]; return self::$structs[$route_file]['instance']; } /** * * 实现细节: * 根据当前app的路由配置,查找到指定条目,并将当前path里携带的参数存放进 $_GET和$_REQUEST变量里 * 对当前请求路由 * */ public function rewrite() { $path = Request::getInstance()->path(); $rules = $this->struct['rules']; foreach ($rules as $pattern => $rule) { $pattern = "#^{$pattern}$#"; if (preg_match($pattern, $path, $matches)) { foreach ($rule as $param => $paramVal) { if ($paramVal{0} != '$') { $_GET[$param] = $paramVal; $_REQUEST[$param] = $paramVal; } else { $match_pos = substr($paramVal, 1); if (Verify::naturalNumber($match_pos)) { $_GET[$param] = $matches[$match_pos]; $_REQUEST[$param] = $matches[$match_pos]; } } } break; } } } /** * * 获取经过路由后得到的请求参数。目前该方法被 Request::pageUrlTpl使用 * @return array 如果没有对应的路由,返回空数组 */ public function getsRouteParams() { $route_params = array(); $path = Request::getInstance()->path(); $rules = $this->struct['rules']; foreach ($rules as $pattern => $rule) { $pattern = "#^{$pattern}$#"; if (preg_match($pattern, $path, $matches)) { foreach ($rule as $param => $paramVal) { if ($paramVal{0} != '$') { $route_params[$param] = $paramVal; } else { $match_pos = substr($paramVal, 1); if (Verify::naturalNumber($match_pos)) { $route_params[$param] = $matches[$match_pos]; } } } break; } } return $route_params; } /** * * 反向rewrite。通过 $args 给定的参数,逆向rewrite规则,获取rewrite的url * @param array $args 给定的参数值 * @return String */ public function reverse(array $args) { if (!$args) { return false; } if (!isset($args['a'])) { $args['a'] = 'default'; } $arg_fingerprint = $this->generateFingerprint($args); if (isset($this->struct['reverse_rules'][$arg_fingerprint])) { $rewrite_pattern = $this->struct['reverse_rules'][$arg_fingerprint]; if (strpos($rewrite_pattern, '(') === false) { return $rewrite_pattern; } $rule = $this->struct['rules'][$rewrite_pattern]; $rule = array_filter($rule, function ($tmpV) { if ($tmpV{0} != '$') { return false; } return $tmpV; }); $match_times = 0; $url = preg_replace_callback('#\([^)]+\)#', function ($matches) use (& $match_times, $rule, $args) { $match_times++; $key = array_search("\${$match_times}", $rule); if (!$key) { return false; } if (!isset($args[$key])) { return false; } return $args[$key]; }, $rewrite_pattern); if (is_null($url)) {//说明发生错误了。 return String::jointUrl('', $args); } return $url; } return String::jointUrl('', $args); } }