<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                [TOC] * * * * * #1 路由解析 >>路由解析的實現在(library/Route.php)中 >路由 將Url分派到指定的應用處理邏輯部分。 >>Url路由 主要包括路由注冊與路由檢測兩部分 >路由注冊 注冊Url路由規則到Route中 >路由檢測 根據Route解析網絡請求Url到應用處理邏輯部分。 >注冊路由規則 , 指的是 (請求對象的url)與(應用層的應用地址)的對應關系 >路由規則的解析,就是在注冊的路由規則中查找請求對象url,對應的應用地址。 >由 [應用組織](http://www.hmoore.net/zmwtp/tp/210988) 章節可知,tp將應用組織為6種類型,在路由規則中,可以注冊5種類型的應用地址(module,controller,method,function,redirect,)為url的對應處理邏輯。 #2 路由規則 >> 路由規則主要實現Url信息與應用地址信息的關聯 >Url信息 主要是網絡請求的Url參數信息。如域名,請求類型,請求的控制器,操作,url參數等 >應用地址信息 主要是應用層對應的Url處理邏輯地址標識信息。 >根據應用組織的不同類型應用表示為不同形式的應用地址格式。 >路由規則的注冊形式 包括配置文件注冊,Route對應方法注冊。 >配置文件的注冊的實現分為加載路由配置文件,然后調用Route對應的注冊方法。 ## 2-1 Url信息 >> Url信息可以由網絡請求對象(Request)的對應方法獲取 >具有信息查看[網絡請求(Request)](http://www.hmoore.net/zmwtp/tp/210989)章節 ## 2-2 應用地址信息 >> 應用地址信息 根據不同形式的應用類型分為以下5種 >模塊/控制器地址 >重定向地址 >控制器方法 >類的方法 >閉包函數 ### 1 模塊/控制器類應用地址 >> 模塊/控制器應用是最為常見的基礎應用類型。 > 模塊/控制器地址格式為 [模塊/控制器]操作?參數1=值1&參數2=值2... ~~~ ; 配置文件格式 'blog/:id'=>'blog/read', 'blog/:id'=>'index/blog/read', 'blog/:id'=>'blog/read?status=1&app_id=5', ;Route方法格式 Route::rule('blog/:id','blog/read'); Route::rule('blog/:id','index/blog/read'); Route::rule('blog/:id','blog/read?status=1&app_id=5'); ~~~ ### 2 重定向類應用地址 >>重定向應用必須以"/"或者"http"開頭 ~~~ ; 重定向地址格式 'blog/:id'=>'/blog/read/id/:id' 'blog/:id'=>'http://blog.thinkphp.cn/read/:id' Route::rule('blog/:id','/blog/read/id/:id'); Route::rule('blog/:id','http://blog.thinkphp.cn/read/:id'); ~~~ ### 3 控制器操作類應用地址 >> Url信息直接解析到特定控制器的操作地址 >格式為:@[模塊/控制器/]操作 ~~~ 'blog/:id'=>'@index/blog/read', Route::rule('blog/:id','@index/blog/read'); ~~~ ### 4 類的方法類應用地址 >>Url信息解析到類的方法 >格式為:\類的命名空間\類名@方法名或者\類的命名空間\類名::方法名 ~~~ 'blog/:id'=>'\app\index\service\Blog@read', 'blog/:id'=>'\app\index\service\Blog::read', Route::rule('blog/:id',''\app\index\service\Blog@read'); Route::rule('blog/:id',''\app\index\service\Blog::read'); ~~~ ### 5 閉包函數類應用地址 >> Url信息直接執行閉包函數應用 > 將閉包函數作為參數 ~~~ Route::get('hello',function(){ return 'hello,world!'; }); Route::get('hello/:name',function($name){ return 'Hello,'.$name; }); ~~~ ## 2-3 注冊形式 ### 配置文件注冊 >>配置文件注冊在application/route.php中定義 ~~~ return [ 'new/:id' => 'News/read', 'blog/:id' => ['Blog/update',['method' => 'post|put'], ['id' => '\d+']], ]; ~~~ ### Route方法注冊 >>配置文件中也可以使用Route方法進行注冊 >最后需要返回一個數組作為配置文件的返回內容 ~~~ ;Route方法注冊路由 Route::rule([ ['blog/:id','Blog/read',['method'=>'get']], ['blog/:id','Blog/update',['method'=>'post']], ... ],'','*',['ext'=>'html'],['id'=>'\d+']); ~~~ ~~~ ;兩種形式路由注冊 use think\Route; Route::rule('hello/:name','index/index/hello'); return [ 'new/:id' => 'News/read', 'blog/:id' => ['Blog/update',['method' => 'post|put'], ['id' => '\d+']], ]; ~~~ >配置文件的位置可以自定義如下 ~~~ // 定義路由配置文件(數組) 'route_config_file' => ['route', 'route1', 'route2'], ~~~ #3 路由注冊 >>路由規則的注冊按照層次分為三個類型 >類型注冊 >注冊核心 >參數選項 ## 3-1 類型注冊 ### get類型 ~~~ public static function get($rule, $route = '', $option = [], $pattern = []) { self::rule($rule, $route, 'GET', $option, $pattern); } ~~~ ### post類型 ~~~ public static function get($rule, $route = '', $option = [], $pattern = []) { self::rule($rule, $route, 'GET', $option, $pattern); } ~~~ ### put類型 ~~~ public static function put($rule, $route = '', $option = [], $pattern = []) { self::rule($rule, $route, 'PUT', $option, $pattern); } ~~~ ### delete類型 ~~~ public static function delete($rule, $route = '', $option = [], $pattern = []) { self::rule($rule, $route, 'DELETE', $option, $pattern); } ~~~ ### any類型 ~~~ public static function any($rule, $route = '', $option = [], $pattern = []) { self::rule($rule, $route, '*', $option, $pattern); } ~~~ ### patch類型 ~~~ public static function patch($rule, $route = '', $option = [], $pattern = []) { self::rule($rule, $route, 'PATCH', $option, $pattern); } ~~~ ### resource類型 ~~~ public static function resource($rule, $route = '', $option = [], $pattern = []) { if (is_array($rule)) { foreach ($rule as $key => $val) { if (is_array($val)) { list($val, $option, $pattern) = array_pad($val, 3, []); } self::resource($key, $val, $option, $pattern); } } else { if (strpos($rule, '.')) { // 注冊嵌套資源路由 $array = explode('.', $rule); $last = array_pop($array); $item = []; foreach ($array as $val) { $item[] = $val . '/:' . (isset($option['var'][$val]) ? $option['var'][$val] : $val . '_id'); } $rule = implode('/', $item) . '/' . $last; } // 注冊資源路由 foreach (self::$rest as $key => $val) { if ((isset($option['only']) && !in_array($key, $option['only'])) || (isset($option['except']) && in_array($key, $option['except']))) { continue; } if (isset($last) && strpos($val[1], ':id') && isset($option['var'][$last])) { $val[1] = str_replace(':id', ':' . $option['var'][$last], $val[1]); } elseif (strpos($val[1], ':id') && isset($option['var'][$rule])) { $val[1] = str_replace(':id', ':' . $option['var'][$rule], $val[1]); } $item = ltrim($rule . $val[1], '/'); self::rule($item . '$', $route . '/' . $val[2], $val[0], $option, $pattern); } } } ~~~ ### miss類型 ~~~ public static function miss($route, $method = '*', $option = []) { self::rule('__miss__', $route, $method, $option, []); } ~~~ ### auto類型 ~~~ public static function auto($route) { self::rule('__auto__', $route, '*', [], []); } ~~~ ##3-2 注冊核心 >>各種類型的路由注冊最后都會調用路由的注冊核心(Route::rule()) >Route::rule()會進一步調用注冊的實現Route::setRule() ### Route::rule() ~~~ public static function rule($rule, $route = '', $type = '*', $option = [], $pattern = []) { $group = self::getGroup('name'); if (!is_null($group)) { // 路由分組 $option = array_merge(self::getGroup('option'), $option); $pattern = array_merge(self::getGroup('pattern'), $pattern); } $type = strtoupper($type); if (strpos($type, '|')) { $option['method'] = $type; $type = '*'; } if (is_array($rule) && empty($route)) { foreach ($rule as $key => $val) { if (is_numeric($key)) { $key = array_shift($val); } if (is_array($val)) { $route = $val[0]; $option1 = array_merge($option, $val[1]); $pattern1 = array_merge($pattern, isset($val[2]) ? $val[2] : []); } else { $route = $val; } self::setRule($key, $route, $type, isset($option1) ? $option1 : $option, isset($pattern1) ? $pattern1 : $pattern, $group); } } else { self::setRule($rule, $route, $type, $option, $pattern, $group); } } ~~~ ### Route::setRule() ~~~ protected static function setRule($rule, $route, $type = '*', $option = [], $pattern = [], $group = '') { if (is_array($rule)) { $name = $rule[0]; $rule = $rule[1]; } elseif (is_string($route)) { $name = $route; } if (!isset($option['complete_match'])) { if (Config::get('route_complete_match')) { $option['complete_match'] = true; } elseif ('$' == substr($rule, -1, 1)) { // 是否完整匹配 $option['complete_match'] = true; $rule = substr($rule, 0, -1); } } elseif (empty($option['complete_match']) && '$' == substr($rule, -1, 1)) { // 是否完整匹配 $option['complete_match'] = true; $rule = substr($rule, 0, -1); } if ('/' != $rule) { $rule = trim($rule, '/'); } $vars = self::parseVar($rule); if (isset($name)) { self::name($name, [$rule, $vars, self::$domain]); } if ($group) { if ('*' != $type) { $option['method'] = $type; } if (self::$domain) { self::$rules['domain'][self::$domain]['*'][$group]['rule'][] = ['rule' => $rule, 'route' => $route, 'var' => $vars, 'option' => $option, 'pattern' => $pattern]; } else { self::$rules['*'][$group]['rule'][] = ['rule' => $rule, 'route' => $route, 'var' => $vars, 'option' => $option, 'pattern' => $pattern]; } } else { if ('*' != $type && isset(self::$rules['*'][$rule])) { unset(self::$rules['*'][$rule]); } if (self::$domain) { self::$rules['domain'][self::$domain][$type][$rule] = ['rule' => $rule, 'route' => $route, 'var' => $vars, 'option' => $option, 'pattern' => $pattern]; } else { self::$rules[$type][$rule] = ['rule' => $rule, 'route' => $route, 'var' => $vars, 'option' => $option, 'pattern' => $pattern]; } if ('*' == $type) { // 注冊路由快捷方式 foreach (['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'] as $method) { if (self::$domain) { self::$rules['domain'][self::$domain][$method][$rule] = true; } else { self::$rules[$method][$rule] = true; } } } } } ~~~ ## 3-3 參數選項 #4 注冊擴展 >>路由注冊還包含其他各種擴展信息 >域名的注冊 >路由分組注冊 >路由的綁定注冊 >路由的快捷注冊 >路由變量規則 >rest方法規則修改 >路由別名注冊 ## 4-1 domain域名注冊 >域名注冊包括域名注冊接口(Route::domain())和域名注冊實現(Route::setDomain()) ### 1 Route::domain() ~~~ public static function domain($domain, $rule = '', $option = [], $pattern = []) { if (is_array($domain)) { foreach ($domain as $key => $item) { self::domain($key, $item, $option, $pattern); } } elseif ($rule instanceof \Closure) { // 執行閉包 self::setDomain($domain); call_user_func_array($rule, []); self::setDomain(null); } elseif (is_array($rule)) { self::setDomain($domain); self::group('', function () use ($rule) { // 動態注冊域名的路由規則 self::registerRules($rule); }, $option, $pattern); self::setDomain(null); } else { self::$rules['domain'][$domain]['[bind]'] = [$rule, $option, $pattern]; } } ~~~ ### Route::setDomain() ~~~ private static function setDomain($domain) { self::$domain = $domain; } ~~~ ## 4-2 路由分組 >> 路由分組的注冊包括路由分組接口(Route::group())和路由分組實現核心(Route::setGroup()) ### Route::group() ~~~ public static function group($name, $routes, $option = [], $pattern = []) { if (is_array($name)) { $option = $name; $name = isset($option['name']) ? $option['name'] : ''; } // 分組 $currentGroup = self::getGroup('name'); if ($currentGroup) { $name = $currentGroup . ($name ? '/' . ltrim($name, '/') : ''); } if (!empty($name)) { if ($routes instanceof \Closure) { $currentOption = self::getGroup('option'); $currentPattern = self::getGroup('pattern'); self::setGroup($name, array_merge($currentOption, $option), array_merge($currentPattern, $pattern)); call_user_func_array($routes, []); self::setGroup($currentGroup, $currentOption, $currentPattern); if ($currentGroup != $name) { self::$rules['*'][$name]['route'] = ''; self::$rules['*'][$name]['var'] = self::parseVar($name); self::$rules['*'][$name]['option'] = $option; self::$rules['*'][$name]['pattern'] = $pattern; } } else { $item = []; foreach ($routes as $key => $val) { if (is_numeric($key)) { $key = array_shift($val); } if (is_array($val)) { $route = $val[0]; $option1 = array_merge($option, isset($val[1]) ? $val[1] : []); $pattern1 = array_merge($pattern, isset($val[2]) ? $val[2] : []); } else { $route = $val; } $options = isset($option1) ? $option1 : $option; $patterns = isset($pattern1) ? $pattern1 : $pattern; if ('$' == substr($key, -1, 1)) { // 是否完整匹配 $options['complete_match'] = true; $key = substr($key, 0, -1); } $vars = self::parseVar($key); $item[] = ['rule' => $key, 'route' => $route, 'var' => $vars, 'option' => $options, 'pattern' => $patterns]; // 設置路由標識 self::name($route, [$key, $vars, self::$domain]); } self::$rules['*'][$name] = ['rule' => $item, 'route' => '', 'var' => [], 'option' => $option, 'pattern' => $pattern]; } foreach (['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'] as $method) { if (!isset(self::$rules[$method][$name])) { self::$rules[$method][$name] = true; } elseif (is_array(self::$rules[$method][$name])) { self::$rules[$method][$name] = array_merge(self::$rules['*'][$name], self::$rules[$method][$name]); } } } elseif ($routes instanceof \Closure) { // 閉包注冊 $currentOption = self::getGroup('option'); $currentPattern = self::getGroup('pattern'); self::setGroup('', array_merge($currentOption, $option), array_merge($currentPattern, $pattern)); call_user_func_array($routes, []); self::setGroup($currentGroup, $currentOption, $currentPattern); } else { // 批量注冊路由 self::rule($routes, '', '*', $option, $pattern); } } ~~~ ### Route::setGroup() ~~~ public static function setGroup($name, $option = [], $pattern = []) { self::$group['name'] = $name; self::$group['option'] = $option ?: []; self::$group['pattern'] = $pattern ?: []; } ~~~ ## 4-3 路由綁定注冊 >>路由綁定注冊將當前url綁定到特定命名空間(namespace),模塊(module),類(class),控制器(controller) >包括路由綁定接口(Route::bind())和各種類型綁定(Route::bindToxx()) ### Route::bind() ~~~ public static function bind($bind, $type = 'module') { self::$bind = ['type' => $type, $type => $bind]; } ~~~ ### Route::bindToNamespace() ~~~ public static function bindToNamespace($url, $namespace, $depr = '/') { $array = explode($depr, $url, 3); $class = !empty($array[0]) ? $array[0] : Config::get('default_controller'); $method = !empty($array[1]) ? $array[1] : Config::get('default_action'); if (!empty($array[2])) { self::parseUrlParams($array[2]); } return ['type' => 'method', 'method' => [$namespace . '\\' . $class, $method]]; } ~~~ ### Route::bindToModule() ~~~ public static function bindToModule($url, $controller, $depr = '/') { $array = explode($depr, $url, 2); $action = !empty($array[0]) ? $array[0] : Config::get('default_action'); if (!empty($array[1])) { self::parseUrlParams($array[1]); } return ['type' => 'module', 'module' => $controller . '/' . $action]; } ~~~ ### Route::bindToClass() ~~~ public static function bindToClass($url, $class, $depr = '/') { $array = explode($depr, $url, 2); $action = !empty($array[0]) ? $array[0] : Config::get('default_action'); if (!empty($array[1])) { self::parseUrlParams($array[1]); } return ['type' => 'method', 'method' => [$class, $action]]; } ~~~ ### Route::bindToCOntroller() ~~~ public static function bindToController($url, $controller, $depr = '/') { $array = explode($depr, $url, 2); $action = !empty($array[0]) ? $array[0] : Config::get('default_action'); if (!empty($array[1])) { self::parseUrlParams($array[1]); } return ['type' => 'controller', 'controller' => $controller . '/' . $action]; } ~~~ ## 4-4 路由快捷注冊 >>路由快捷注冊包括快捷接口(Route::controller)和請求類型的前綴注冊(Route::setMethodPrefix) ### Route::controller() ~~~ public static function controller($rule, $route = '', $option = [], $pattern = []) { foreach (self::$methodPrefix as $type => $val) { self::$type($rule . '/:action', $route . '/' . $val . ':action', $option, $pattern); } } ~~~ ### Route::setMethodPrefix() >>快捷路由的方法前綴默認為 ~~~ private static $methodPrefix = [ 'GET' => 'get', 'POST' => 'post', 'PUT' => 'put', 'DELETE' => 'delete', ]; ~~~ >可以使用Route::setMethodPrefix()重定義快捷路由方法前綴 ~~~ public static function setMethodPrefix($method, $prefix = '') { if (is_array($method)) { self::$methodPrefix = array_merge(self::$methodPrefix, array_change_key_case($method, CASE_UPPER)); } else { self::$methodPrefix[strtoupper($method)] = $prefix; } } ~~~ ## 4-5 路由變量規則 >>Route::pattern()注冊和獲取變量正則規則 ### Route::pattern() ~~~ public static function pattern($name = null, $rule = '') { if (is_array($name)) { self::$rules['pattern'] = array_merge(self::$rules['pattern'], $name); } else { self::$rules['pattern'][$name] = $rule; } } ~~~ ## 4-6 rest方法格式修改 >>Route::rest()修改rest默認的規則格式 >默認的rest的規則格式為 ~~~ private static $rest = [ 'index' => ['GET', '', 'index'], 'create' => ['GET', '/create', 'create'], 'edit' => ['GET', '/:id/edit', 'edit'], 'read' => ['GET', '/:id', 'read'], 'save' => ['POST', '', 'save'], 'update' => ['PUT', '/:id', 'update'], 'delete' => ['DELETE', '/:id', 'delete'], ]; ~~~ >可以使用Route::rest()方法重定義rest方法格式 ### Route::rest() ~~~ public static function rest($name, $resource = []) { if (is_array($name)) { self::$rest = array_merge(self::$rest, $name); } else { self::$rest[$name] = $resource; } } ~~~ ## 4-7 路由別名注冊 >>Route::alias()可以注冊路由的別名 ### Route::alias() ~~~ public static function alias($rule = null, $route = '', $option = []) { if (is_array($rule)) { self::$rules['alias'] = array_merge(self::$rules['alias'], $rule); } else { self::$rules['alias'][$rule] = $option ? [$route, $option] : $route; } } ~~~ #5 路由解析 >>路由解析 根據Url信息查找獲取對應的應用地址。 >按照查找的層次分為以下 >Url有效性檢測 >Url對應路由規則查找 >Url參數解析 ## 5-1 Url有效性檢測 >>Url有效性檢測,包括以下 >Url檢測入口Route::check() >路由別名檢測Route::checkRouteAlias() >Url域名檢測Route::checkDomain() >Url綁定檢測Route::checkBind() ### Route::check() ~~~ public static function check($request, $url, $depr = '/', $checkDomain = false) { // 分隔符替換 確保路由定義使用統一的分隔符 if ('/' != $depr) { $url = str_replace($depr, '/', $url); } if (strpos($url, '/') && isset(self::$rules['alias'][strstr($url, '/', true)])) { // 檢測路由別名 $result = self::checkRouteAlias($request, $url, $depr); if (false !== $result) { return $result; } } $method = $request->method(); // 獲取當前請求類型的路由規則 $rules = self::$rules[$method]; // 檢測域名部署 if ($checkDomain) { self::checkDomain($request, $rules, $method); } // 檢測URL綁定 $return = self::checkUrlBind($url, $rules, $depr); if (false !== $return) { return $return; } if ('/' != $url) { $url = rtrim($url, '/'); } if (isset($rules[$url])) { // 靜態路由規則檢測 $rule = $rules[$url]; if (true === $rule) { $rule = self::getRouteExpress($url); } if (!empty($rule['route'])) { return self::parseRule($url, $rule['route'], $url, $rule['option']); } } // 路由規則檢測 if (!empty($rules)) { return self::checkRoute($request, $rules, $url, $depr); } return false; } ~~~ ### Route::checkRouteAlias() >>路由別名檢測checkRouteAlias()中 >首先獲取別名對應的路由規則 >然后檢查參數的有效性Route::checkOption() >最后進行Url格式中綁定類型的檢測 ~~~ private static function checkRouteAlias($request, $url, $depr) { $array = explode('/', $url, 2); $item = self::$rules['alias'][$array[0]]; if (is_array($item)) { list($rule, $option) = $item; } else { $rule = $item; } // 參數有效性檢查 if (isset($option) && !self::checkOption($option, $url, $request)) { // 路由不匹配 return false; } elseif (0 === strpos($rule, '\\')) { // 路由到類 return self::bindToClass($array[1], substr($rule, 1), $depr); } elseif (0 === strpos($url, '@')) { // 路由到控制器類 return self::bindToController($array[1], substr($rule, 1), $depr); } else { // 路由到模塊/控制器 return self::bindToModule($array[1], $rule, $depr); } } ~~~ ### Route::checkDomain() >>域名規則檢測checkDomain()中 >首先獲取網絡請求域名(host)對應的注冊的域名規則(rules['domain]) >然后將url相關參數拼接到新的域名規則url中 >最后進行綁定類型的檢測與轉換 ~~~ public static function checkDomain($request, &$currentRules, $method = 'GET') { // 域名規則 $rules = self::$rules['domain']; // 開啟子域名部署 支持二級和三級域名 if (!empty($rules)) { $host = $request->host(); if (isset($rules[$host])) { // 完整域名或者IP配置 $item = $rules[$host]; } else { $rootDomain = Config::get('url_domain_root'); if ($rootDomain) { // 配置域名根 例如 thinkphp.cn 163.com.cn 如果是國家級域名 com.cn net.cn 之類的域名需要配置 $domain = explode('.', rtrim(stristr($host, $rootDomain, true), '.')); } else { $domain = explode('.', $host, -2); } // 子域名配置 if (!empty($domain)) { // 當前子域名 $subDomain = implode('.', $domain); self::$subDomain = $subDomain; $domain2 = array_pop($domain); if ($domain) { // 存在三級域名 $domain3 = array_pop($domain); } if ($subDomain && isset($rules[$subDomain])) { // 子域名配置 $item = $rules[$subDomain]; } elseif (isset($rules['*.' . $domain2]) && !empty($domain3)) { // 泛三級域名 $item = $rules['*.' . $domain2]; $panDomain = $domain3; } elseif (isset($rules['*']) && !empty($domain2)) { // 泛二級域名 if ('www' != $domain2) { $item = $rules['*']; $panDomain = $domain2; } } } } if (!empty($item)) { if (isset($item['[bind]'])) { // 解析子域名部署規則 list($rule, $option, $pattern) = $item['[bind]']; if (!empty($option['https']) && !$request->isSsl()) { // https檢測 throw new HttpException(404, 'must use https request:' . $host); } if (strpos($rule, '?')) { // 傳入其它參數 $array = parse_url($rule); $result = $array['path']; parse_str($array['query'], $params); if (isset($panDomain)) { $pos = array_search('*', $params); if (false !== $pos) { // 泛域名作為參數 $params[$pos] = $panDomain; } } $_GET = array_merge($_GET, $params); } else { $result = $rule; } if (0 === strpos($result, '\\')) { // 綁定到命名空間 例如 \app\index\behavior self::$bind = ['type' => 'namespace', 'namespace' => $result]; } elseif (0 === strpos($result, '@')) { // 綁定到類 例如 @app\index\controller\User self::$bind = ['type' => 'class', 'class' => substr($result, 1)]; } else { // 綁定到模塊/控制器 例如 index/user self::$bind = ['type' => 'module', 'module' => $result]; } self::$domainBind = true; } else { self::$domainRule = $item; $currentRules = isset($item[$method]) ? $item[$method] : $item['*']; } } } } ~~~ ### Route::checkUrlBind() >>Url綁定檢測checkUrlBind()中 >首先獲取綁定類型 >然后根據綁定類型解析為不同的綁定規則 ~~~ private static function checkUrlBind(&$url, &$rules, $depr = '/') { if (!empty(self::$bind)) { $type = self::$bind['type']; $bind = self::$bind[$type]; // 記錄綁定信息 App::$debug && Log::record('[ BIND ] ' . var_export($bind, true), 'info'); // 如果有URL綁定 則進行綁定檢測 switch ($type) { case 'class': // 綁定到類 return self::bindToClass($url, $bind, $depr); case 'namespace': // 綁定到命名空間 return self::bindToNamespace($url, $bind, $depr); case 'module': // 如果有模塊/控制器綁定 針對路由到 模塊/控制器 有效 $url = (empty(self::$domainBind) ? $bind . '/' : '') . ltrim($url, '/'); break; } } return false; } ~~~ ## 5-2 Url路由規則查找 >>Url路由規則查找包括靜態路由查找和非靜態路由查找 >靜態路由檢測Route::getRouteExpress() >Url規則解析Route::parseRule() >路由規則檢測Route::checkRoute() ### Route::getRouteExpress() >>靜態路由檢測 url直接對應的路由規則 >首先獲取注冊的靜態路由規則 >然后調用parseRule()解析路由規則 ~~~ private static function getRouteExpress($key) { return self::$domainRule ? self::$domainRule['*'][$key] : self::$rules['*'][$key]; } ~~~ ### Route::parseRule() >>路由規則解析parseRule() >首先解析路由規則的url參數信息 >然后解析路由規則的對應Option選項參數到路由地址 >檢測是否綁定到模型 >然后合并Url的額外參數 >記錄路由信息到網絡請求 >執行路由檢查的后調after_behavior鉤子 >最后根據地址route的不同類型組裝不同類型的應用路由 ~~~ private static function parseRule($rule, $route, $pathinfo, $option = [], $matches = [], $merge = false) { // 解析路由規則變量 if ($rule) { $rule = explode('/', $rule); // 獲取URL地址中的參數 $paths = $merge ? explode('/', $pathinfo, count($rule)) : explode('/', $pathinfo); foreach ($rule as $item) { $fun = ''; if (0 === strpos($item, '[:')) { $item = substr($item, 1, -1); } if (0 === strpos($item, ':')) { $var = substr($item, 1); $matches[$var] = array_shift($paths); } else { // 過濾URL中的靜態變量 array_shift($paths); } } } else { $paths = explode('/', $pathinfo); } // 獲取路由地址規則 if (is_string($route) && isset($option['prefix'])) { // 路由地址前綴 $route = $option['prefix'] . $route; } // 替換路由地址中的變量 if (is_string($route) && !empty($matches)) { foreach ($matches as $key => $val) { if (false !== strpos($route, ':' . $key)) { $route = str_replace(':' . $key, $val, $route); unset($matches[$key]); } } } // 綁定模型數據 if (isset($option['bind_model'])) { $bind = []; foreach ($option['bind_model'] as $key => $val) { if ($val instanceof \Closure) { $result = call_user_func_array($val, [$matches]); } else { if (is_array($val)) { $fields = explode('&', $val[1]); $model = $val[0]; $exception = isset($val[2]) ? $val[2] : true; } else { $fields = ['id']; $model = $val; $exception = true; } $where = []; $match = true; foreach ($fields as $field) { if (!isset($matches[$field])) { $match = false; break; } else { $where[$field] = $matches[$field]; } } if ($match) { $query = strpos($model, '\\') ? $model::where($where) : Loader::model($model)->where($where); $result = $query->failException($exception)->find(); } } if (!empty($result)) { $bind[$key] = $result; } } Request::instance()->bind($bind); } // 解析額外參數 self::parseUrlParams(empty($paths) ? '' : implode('/', $paths), $matches); // 記錄匹配的路由信息 Request::instance()->routeInfo(['rule' => $rule, 'route' => $route, 'option' => $option, 'var' => $matches]); // 檢測路由after行為 if (!empty($option['after_behavior'])) { if ($option['after_behavior'] instanceof \Closure) { $result = call_user_func_array($option['after_behavior'], []); } else { foreach ((array) $option['after_behavior'] as $behavior) { $result = Hook::exec($behavior, ''); if (!is_null($result)) { break; } } } // 路由規則重定向 if ($result instanceof Response) { return ['type' => 'response', 'response' => $result]; } elseif (is_array($result)) { return $result; } } if ($route instanceof \Closure) { // 執行閉包 $result = ['type' => 'function', 'function' => $route]; } elseif (0 === strpos($route, '/') || 0 === strpos($route, 'http')) { // 路由到重定向地址 $result = ['type' => 'redirect', 'url' => $route, 'status' => isset($option['status']) ? $option['status'] : 301]; } elseif (0 === strpos($route, '\\')) { // 路由到方法 $method = strpos($route, '@') ? explode('@', $route) : $route; $result = ['type' => 'method', 'method' => $method]; } elseif (0 === strpos($route, '@')) { // 路由到控制器 $result = ['type' => 'controller', 'controller' => substr($route, 1)]; } else { // 路由到模塊/控制器/操作 $result = self::parseModule($route); } return $result; } ~~~ ### Route::checkRoute() >>如果Url直接對應的路由規則為空。 >則進行miss和auto路由檢測 ~~~ private static function checkRoute($request, $rules, $url, $depr = '/', $group = '', $options = []) { foreach ($rules as $key => $item) { if (true === $item) { $item = self::getRouteExpress($key); } if (!isset($item['rule'])) { continue; } $rule = $item['rule']; $route = $item['route']; $vars = $item['var']; $option = $item['option']; $pattern = $item['pattern']; // 檢查參數有效性 if (!self::checkOption($option, $url, $request)) { continue; } if (isset($option['ext'])) { // 路由ext參數 優先于系統配置的URL偽靜態后綴參數 $url = preg_replace('/\.' . $request->ext() . '$/i', '', $url); } if (is_array($rule)) { // 分組路由 $pos = strpos(str_replace('<', ':', $key), ':'); if (false !== $pos) { $str = substr($key, 0, $pos); } else { $str = $key; } if (is_string($str) && $str && 0 !== strpos($url, $str)) { continue; } $result = self::checkRoute($request, $rule, $url, $depr, $key, $option); if (false !== $result) { return $result; } } elseif ($route) { if ('__miss__' == $rule || '__auto__' == $rule) { // 指定特殊路由 $var = trim($rule, '__'); ${$var} = $item; continue; } if ($group) { $rule = $group . ($rule ? '/' . ltrim($rule, '/') : ''); } if (isset($options['bind_model']) && isset($option['bind_model'])) { $option['bind_model'] = array_merge($options['bind_model'], $option['bind_model']); } $result = self::checkRule($rule, $route, $url, $pattern, $option); if (false !== $result) { return $result; } } } if (isset($auto)) { // 自動解析URL地址 return self::parseUrl($auto['route'] . '/' . $url, $depr); } elseif (isset($miss)) { // 未匹配所有路由的路由規則處理 return self::parseRule('', $miss['route'], $url, $miss['option']); } return false; } ~~~ ## 5-3 Url參數解析 >>Url參數解析是在路由解析過程中調用的子過程,包括以下 >Url解析入口 >UrlPath解析 >Url參數解析 >Module解析 ### Route::parseUrl() ~~~ public static function parseUrl($url, $depr = '/', $autoSearch = false) { if (isset(self::$bind['module'])) { // 如果有模塊/控制器綁定 $url = self::$bind['module'] . '/' . ltrim($url, '/'); } list($path, $var) = self::parseUrlPath($url, $depr); $route = [null, null, null]; if (isset($path)) { // 解析模塊 $module = Config::get('app_multi_module') ? array_shift($path) : null; if ($autoSearch) { // 自動搜索控制器 $dir = APP_PATH . ($module ? $module . DS : '') . 'controller'; $suffix = App::$suffix || Config::get('controller_suffix') ? ucfirst(Config::get('url_controller_layer')) : ''; $item = []; foreach ($path as $val) { $item[] = array_shift($path); if (is_file($dir . DS . $val . $suffix . EXT)) { break; } else { $dir .= DS . $val; } } $controller = implode('.', $item); } else { // 解析控制器 $controller = !empty($path) ? array_shift($path) : null; } // 解析操作 $action = !empty($path) ? array_shift($path) : null; // 解析額外參數 self::parseUrlParams(empty($path) ? '' : implode('/', $path)); // 封裝路由 $route = [$module, $controller, $action]; if (isset(self::$rules['name'][implode($depr, $route)])) { throw new HttpException(404, 'invalid request:' . $url); } } return ['type' => 'module', 'module' => $route]; } ~~~ ### Route::parseUrlPath() ~~~ private static function parseUrlPath($url, $depr = '/') { // 分隔符替換 確保路由定義使用統一的分隔符 if ('/' != $depr) { $url = str_replace($depr, '/', $url); } $url = trim($url, '/'); $var = []; if (false !== strpos($url, '?')) { // [模塊/控制器/操作?]參數1=值1&參數2=值2... $info = parse_url($url); $path = explode('/', $info['path']); parse_str($info['query'], $var); } elseif (strpos($url, '/')) { // [模塊/控制器/操作] $path = explode('/', $url); } elseif (false !== strpos($url, '=')) { // 參數1=值1&參數2=值2... parse_str($url, $var); } else { $path = [$url]; } return [$path, $var]; } ~~~ ### Route::parseUrlParams() ~~~ private static function parseUrlParams($url, &$var = []) { if ($url) { if (Config::get('url_param_type')) { $var += explode('/', $url); } else { preg_replace_callback('/(\w+)\/([^\/]+)/', function ($match) use (&$var) { $var[$match[1]] = strip_tags($match[2]); }, $url); } } // 設置當前請求的參數 Request::instance()->route($var); } ~~~ ### Route::parseModule() >>在模塊/控制/操作類型的應用中調用parseModule() >解析url到對應的類型應用 ~~~ private static function parseModule($url, $depr = '/') { list($path, $var) = self::parseUrlPath($url, $depr); $action = array_pop($path); $controller = !empty($path) ? array_pop($path) : null; $module = Config::get('app_multi_module') && !empty($path) ? array_pop($path) : null; $method = Request::instance()->method(); if (Config::get('use_action_prefix') && !empty(self::$methodPrefix[$method])) { // 操作方法前綴支持 $action = 0 !== strpos($action, self::$methodPrefix[$method]) ? self::$methodPrefix[$method] . $action : $action; } // 設置當前請求的路由變量 Request::instance()->route($var); // 路由到模塊/控制器/操作 return ['type' => 'module', 'module' => [$module, $controller, $action], 'convert' => false]; } ~~~ ### Route::parseVar() >>parseVar()解析規則的變量信息 >默認的變量規則為?,[:,:三種 >也可以注冊變量規則 ~~~ private static function parseVar($rule) { // 提取路由規則中的變量 $var = []; foreach (explode('/', $rule) as $val) { $optional = false; if (false !== strpos($val, '<') && preg_match_all('/<(\w+(\??))>/', $val, $matches)) { foreach ($matches[1] as $name) { if (strpos($name, '?')) { $name = substr($name, 0, -1); $optional = true; } else { $optional = false; } $var[$name] = $optional ? 2 : 1; } } if (0 === strpos($val, '[:')) { // 可選參數 $optional = true; $val = substr($val, 1, -1); } if (0 === strpos($val, ':')) { // URL變量 $name = substr($val, 1); $var[$name] = $optional ? 2 : 1; } } return $var; } ~~~
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看