改進(jìn)
緊接上一篇文章Just for fun——PHP框架之簡單的路由器(1)。
代碼下載
對于以下合并的正則
~^(?: /user/([^/]+)/(d+) | /user/(d+) | /user/([^/]+) )$~x
最終匹配的是分組中的某一個(gè),我們需要的子匹配也是那個(gè)分組中的,然而從結(jié)果看
preg_match($regex, "/user/nikic", $matches); => [ "/user/nikic", # 完全匹配 "", "", # 第一個(gè)(空) "", # 第二個(gè)(空) "nikic", # 第三個(gè)(被使用) ]
這里是最后一個(gè)路由被匹配了,但是其他分組的子匹配也被填充了,這是多余的。
解決思路PCRE正則里?|也是非捕獲分組,那么?|和?:有什么區(qū)別呢??
區(qū)別在于?|會組號重置,看以下幾個(gè)例子就懂了
preg_match("~(?:(Sat)ur|(Sun))day~", "Saturday", $matches) => ["Saturday", "Sat", ""] # 最后一個(gè)""其實(shí)是不存在的,寫在這里是為了闡釋概念 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"]
所有我們可以用?|來代替?:來減少多余的子匹配填充,但是這樣一來的話,如何判斷哪個(gè)分組被匹配了呢??(因?yàn)橹暗呐袛嗉记删褪Я耍?br>我們可以這樣,添加一些多余子匹配
~^(?| /user/([^/]+)/(d+) | /user/(d+)()() | /user/([^/]+)()()() )$~x實(shí)現(xiàn) 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; } }
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/26125.html
摘要:路由路由的功能就是分發(fā)請求到不同的控制器,基于的原理就是正則匹配。 路由 路由的功能就是分發(fā)請求到不同的控制器,基于的原理就是正則匹配。接下來呢,我們實(shí)現(xiàn)一個(gè)簡單的路由器,實(shí)現(xiàn)的能力是 對于靜態(tài)的路由(沒占位符的),正確調(diào)用callback 對于有占位符的路由,正確調(diào)用callback時(shí)傳入占位符參數(shù),譬如對于路由:/user/{id},當(dāng)請求為/user/23時(shí),傳入?yún)?shù)$args...
摘要:使開發(fā)人員可以編寫高性能的異步并發(fā),服務(wù)。使用作為網(wǎng)絡(luò)通信框架,可以使企業(yè)研發(fā)團(tuán)隊(duì)的效率大大提升,更加專注于開發(fā)創(chuàng)新產(chǎn)品??傊@個(gè)庫讓可以常駐內(nèi)存,并提供了,等功能。 swoole 使 PHP 開發(fā)人員可以編寫高性能的異步并發(fā) TCP、UDP、Unix Socket、HTTP,WebSocket 服務(wù)。Swoole 可以廣泛應(yīng)用于互聯(lián)網(wǎng)、移動通信、企業(yè)軟件、云計(jì)算、網(wǎng)絡(luò)游戲、物聯(lián)網(wǎng)(...
摘要:使開發(fā)人員可以編寫高性能的異步并發(fā),服務(wù)。使用作為網(wǎng)絡(luò)通信框架,可以使企業(yè)研發(fā)團(tuán)隊(duì)的效率大大提升,更加專注于開發(fā)創(chuàng)新產(chǎn)品。總之,這個(gè)庫讓可以常駐內(nèi)存,并提供了,等功能。 swoole 使 PHP 開發(fā)人員可以編寫高性能的異步并發(fā) TCP、UDP、Unix Socket、HTTP,WebSocket 服務(wù)。Swoole 可以廣泛應(yīng)用于互聯(lián)網(wǎng)、移動通信、企業(yè)軟件、云計(jì)算、網(wǎng)絡(luò)游戲、物聯(lián)網(wǎng)(...
摘要:原理使用模板引擎的好處是數(shù)據(jù)和視圖分離。對于循環(huán)語句怎么辦呢這個(gè)的話,請看流程控制的替代語法 原理 使用模板引擎的好處是數(shù)據(jù)和視圖分離。一個(gè)簡單的PHP模板引擎原理是 extract數(shù)組($data),使key對應(yīng)的變量可以在此作用域起效 打開輸出控制緩沖(ob_start) include模板文件,include遇到html的內(nèi)容會輸出,但是因?yàn)榇蜷_了緩沖,內(nèi)容輸出到了緩沖中 ob...
摘要:的話,是一個(gè)遵循規(guī)范微型的框架,作者這樣說大致意思的核心工作分發(fā)了請求,然后調(diào)用回調(diào)函數(shù),返回一個(gè)對象。執(zhí)行的方法時(shí),我們從中取出的依賴,這時(shí)候,注冊的回調(diào)函數(shù)被調(diào)用,返回實(shí)例。 Slim Slim的話,是一個(gè)遵循PSR (PSR-7)規(guī)范微型的框架,作者這樣說: Slim is a PHP micro framework that helps you quickly write si...
閱讀 1773·2021-11-12 10:36
閱讀 1675·2021-11-12 10:36
閱讀 3510·2021-11-02 14:46
閱讀 3907·2019-08-30 15:56
閱讀 3729·2019-08-30 15:55
閱讀 1528·2019-08-30 15:44
閱讀 1111·2019-08-30 14:00
閱讀 2781·2019-08-29 18:41