改進
緊接上一篇文章Just for fun——PHP框架之簡單的路由器(1)。
代碼下載
對于以下合并的正則
~^(?: /user/([^/]+)/(d+) | /user/(d+) | /user/([^/]+) )$~x
最終匹配的是分組中的某一個,我們需要的子匹配也是那個分組中的,然而從結果看
preg_match($regex, "/user/nikic", $matches); => [ "/user/nikic", # 完全匹配 "", "", # 第一個(空) "", # 第二個(空) "nikic", # 第三個(被使用) ]
這里是最后一個路由被匹配了,但是其他分組的子匹配也被填充了,這是多余的。
解決思路PCRE正則里?|也是非捕獲分組,那么?|和?:有什么區(qū)別呢??
區(qū)別在于?|會組號重置,看以下幾個例子就懂了
preg_match("~(?:(Sat)ur|(Sun))day~", "Saturday", $matches) => ["Saturday", "Sat", ""] # 最后一個""其實是不存在的,寫在這里是為了闡釋概念 preg_match("~(?:(Sat)ur|(Sun))day~", "Sunday", $matches) => ["Sunday", "", "Sun"] preg_match("~(?|(Sat)ur|(Sun))day~", "Saturday", $matches) => ["Saturday", "Sat"] preg_match("~(?|(Sat)ur|(Sun))day~", "Sunday", $matches) => ["Sunday", "Sun"]
所有我們可以用?|來代替?:來減少多余的子匹配填充,但是這樣一來的話,如何判斷哪個分組被匹配了呢??(因為之前的判斷技巧就失效了)
我們可以這樣,添加一些多余子匹配
~^(?| /user/([^/]+)/(d+) | /user/(d+)()() | /user/([^/]+)()()() )$~x實現 dispatcher.php
1) { preg_match_all("~{([a-zA-Z0-9_]+?)}~", $route, $matchesVariables); return [ preg_replace("~{[a-zA-Z0-9_]+?}~", "([a-zA-Z0-9_]+)", $route), $matchesVariables[1], ]; } else { return [ $route, [], ]; } } throw new LogicException("register route failed, pattern is illegal"); } /** * 注冊路由 * @param $httpMethod string | string[] * @param $route * @param $handler */ public function addRoute($httpMethod, $route, $handler) { $routeData = $this->parse($route); foreach ((array) $httpMethod as $method) { if ($this->isStaticRoute($routeData)) { $this->addStaticRoute($method, $routeData, $handler); } else { $this->addVariableRoute($method, $routeData, $handler); } } } private function isStaticRoute($routeData) { return count($routeData[1]) === 0; } private function addStaticRoute($httpMethod, $routeData, $handler) { $routeStr = $routeData[0]; if (isset($this->staticRoutes[$httpMethod][$routeStr])) { throw new LogicException(sprintf( "Cannot register two routes matching "%s" for method "%s"", $routeStr, $httpMethod )); } if (isset($this->methodToRegexToRoutesMap[$httpMethod])) { foreach ($this->methodToRegexToRoutesMap[$httpMethod] as $route) { if ($route->matches($routeStr)) { throw new LogicException(sprintf( "Static route "%s" is shadowed by previously defined variable route "%s" for method "%s"", $routeStr, $route->regex, $httpMethod )); } } } $this->staticRoutes[$httpMethod][$routeStr] = $handler; } private function addVariableRoute($httpMethod, $routeData, $handler) { list($regex, $variables) = $routeData; if (isset($this->methodToRegexToRoutesMap[$httpMethod][$regex])) { throw new LogicException(sprintf( "Cannot register two routes matching "%s" for method "%s"", $regex, $httpMethod )); } $this->methodToRegexToRoutesMap[$httpMethod][$regex] = new Route( $httpMethod, $handler, $regex, $variables ); } public function get($route, $handler) { $this->addRoute("GET", $route, $handler); } public function post($route, $handler) { $this->addRoute("POST", $route, $handler); } public function put($route, $handler) { $this->addRoute("PUT", $route, $handler); } public function delete($route, $handler) { $this->addRoute("DELETE", $route, $handler); } public function patch($route, $handler) { $this->addRoute("PATCH", $route, $handler); } public function head($route, $handler) { $this->addRoute("HEAD", $route, $handler); } /** * 分發(fā) * @param $httpMethod * @param $uri */ public function dispatch($httpMethod, $uri) { $staticRoutes = array_keys($this->staticRoutes[$httpMethod]); foreach ($staticRoutes as $staticRoute) { if($staticRoute === $uri) { return [self::FOUND, $this->staticRoutes[$httpMethod][$staticRoute], []]; } } $routeLookup = []; $regexes = []; foreach ($this->methodToRegexToRoutesMap[$httpMethod] as $regex => $route) { $index = count($route->variables); if(array_key_exists($index, $routeLookup)) { $indexNear = $this->getArrNearEmptyEntry($routeLookup, $index); array_push($regexes, $regex . str_repeat("()", $indexNear - $index)); $routeLookup[$indexNear] = [ $this->methodToRegexToRoutesMap[$httpMethod][$regex]->handler, $this->methodToRegexToRoutesMap[$httpMethod][$regex]->variables, ]; } else { $routeLookup[$index] = [ $this->methodToRegexToRoutesMap[$httpMethod][$regex]->handler, $this->methodToRegexToRoutesMap[$httpMethod][$regex]->variables, ]; array_push($regexes, $regex); } } $regexCombined = "~^(?|" . implode("|", $regexes) . ")$~"; if(!preg_match($regexCombined, $uri, $matches)) { return [self::NOT_FOUND]; } list($handler, $varNames) = $routeLookup[count($matches) - 1]; $vars = []; $i = 0; foreach ($varNames as $varName) { $vars[$varName] = $matches[++$i]; } return [self::FOUND, $handler, $vars]; } private function getArrNearEmptyEntry(&$arr, $index) { while (array_key_exists(++$index, $arr)); return $index; } }
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/26125.html
摘要:路由路由的功能就是分發(fā)請求到不同的控制器,基于的原理就是正則匹配。 路由 路由的功能就是分發(fā)請求到不同的控制器,基于的原理就是正則匹配。接下來呢,我們實現一個簡單的路由器,實現的能力是 對于靜態(tài)的路由(沒占位符的),正確調用callback 對于有占位符的路由,正確調用callback時傳入占位符參數,譬如對于路由:/user/{id},當請求為/user/23時,傳入參數$args...
摘要:使開發(fā)人員可以編寫高性能的異步并發(fā),服務。使用作為網絡通信框架,可以使企業(yè)研發(fā)團隊的效率大大提升,更加專注于開發(fā)創(chuàng)新產品。總之,這個庫讓可以常駐內存,并提供了,等功能。 swoole 使 PHP 開發(fā)人員可以編寫高性能的異步并發(fā) TCP、UDP、Unix Socket、HTTP,WebSocket 服務。Swoole 可以廣泛應用于互聯網、移動通信、企業(yè)軟件、云計算、網絡游戲、物聯網(...
摘要:使開發(fā)人員可以編寫高性能的異步并發(fā),服務。使用作為網絡通信框架,可以使企業(yè)研發(fā)團隊的效率大大提升,更加專注于開發(fā)創(chuàng)新產品。總之,這個庫讓可以常駐內存,并提供了,等功能。 swoole 使 PHP 開發(fā)人員可以編寫高性能的異步并發(fā) TCP、UDP、Unix Socket、HTTP,WebSocket 服務。Swoole 可以廣泛應用于互聯網、移動通信、企業(yè)軟件、云計算、網絡游戲、物聯網(...
摘要:原理使用模板引擎的好處是數據和視圖分離。對于循環(huán)語句怎么辦呢這個的話,請看流程控制的替代語法 原理 使用模板引擎的好處是數據和視圖分離。一個簡單的PHP模板引擎原理是 extract數組($data),使key對應的變量可以在此作用域起效 打開輸出控制緩沖(ob_start) include模板文件,include遇到html的內容會輸出,但是因為打開了緩沖,內容輸出到了緩沖中 ob...
摘要:的話,是一個遵循規(guī)范微型的框架,作者這樣說大致意思的核心工作分發(fā)了請求,然后調用回調函數,返回一個對象。執(zhí)行的方法時,我們從中取出的依賴,這時候,注冊的回調函數被調用,返回實例。 Slim Slim的話,是一個遵循PSR (PSR-7)規(guī)范微型的框架,作者這樣說: Slim is a PHP micro framework that helps you quickly write si...
閱讀 1699·2021-11-12 10:36
閱讀 1615·2021-11-12 10:36
閱讀 3442·2021-11-02 14:46
閱讀 3798·2019-08-30 15:56
閱讀 3534·2019-08-30 15:55
閱讀 1463·2019-08-30 15:44
閱讀 1044·2019-08-30 14:00
閱讀 2735·2019-08-29 18:41