国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Just for fun——PHP框架之簡單的路由器(1)

smallStone / 2758人閱讀

摘要:路由路由的功能就是分發請求到不同的控制器,基于的原理就是正則匹配。

路由

路由的功能就是分發請求到不同的控制器,基于的原理就是正則匹配。接下來呢,我們實現一個簡單的路由器,實現的能力是

對于靜態的路由(沒占位符的),正確調用callback

對于有占位符的路由,正確調用callback時傳入占位符參數,譬如對于路由:/user/{id},當請求為/user/23時,傳入參數$args結構為

[
    "id" => "23"
]
大致思路

我們需要把每個路由的信息管理起來:http方法($method),路由字符串($route),回調($callback),因此需要一個addRoute方法,另外提供短方法get,post(就是把$method寫好)

對于/user/{id}這樣的有占位符的路由字符串,把占位符要提取出來,然后占位符部分變成正則字符串

代碼講解 路由分類

對于注冊的路由,需要分成兩類(下文提到的$uri是指$_SERVER["REQUEST_URI"]去掉查詢字符串的值)

靜態路由(就是沒有占位符的路由,例如/articles)

帶參數路由(有占位符的路由,例如/user/{uid})

其實這是很明顯的,因為靜態的路由的話,我們只需要和$uri直接比較相等與否就行了,而對于帶參數路由,譬如/user/{uid},我們需要在注冊的時候,提取占位符名,把{**}這一部分替換為([a-zA-Z0-9_]+)這樣的正則字符串,使用()是因為要做分組捕獲,把占位符對應的值要取出來。
Dispatcher.php中有兩個數組

$staticRoutes

$methodToRegexToRoutesMap

分別對應靜態路由和帶參數路由,另外要注意,這兩個數組是二維數組,第一維存儲http method,第二維用來存儲正則字符串(靜態路由自身就是這個值,而帶參數路由是把占位符替換后的值),最后的value是一個Route對象

Route類

這個類很好理解,用來存儲注冊路由的一些信息

$httpMethod:HTTP方法,有GET,POST,PUT,PATCH,HEAD

$regex:路由的正則表達式,帶參數路由是占位符替換后的值,靜態路由自身就是這個值

$variables:路由占位符參數集合,靜態路由就是空數組

$handler:路由要回調的對象

當然,這個類還可以多存儲一點信息,譬如帶參數路由最原始的字符串(/user/{uid}),這里簡單做了

分發流程

根據http method取數據,因為第一維都是http method

一個個匹配靜態路由

對于帶參數路由,把所有的正則表達式合起來,形成一個大的正則字符串,而不是一個個匹配(這樣效率低)

第一步很簡單,主要說明第二步
對于三個獨立的正則字符串(定界符是~):

~^/user/([^/]+)/(d+)$~
~^/user/(d+)$~
~^/user/([^/]+)$~

我們可以合起來,得到

~^(?:
    /user/([^/]+)/(d+)
    | /user/(d+)
    | /user/([^/]+)
)$~x

?:是非捕獲型分組
這個轉化很簡單,我們怎么知道那個正則被匹配了呢??
舉個例子:

preg_match($regex, "/user/nikic", $matches);
=> [
    "/user/nikic",   # 完全匹配
    "", "",          # 第一個(空)
    "",              # 第二個(空)
    "nikic",         # 第三個(被使用)
]

可以看到,第一個非空的位置就可以推斷出哪個路由被匹配了(第一個完全匹配要剔除),我們需要一個數組要映射它

[
    1 => ["handler0", ["name", "id"]],
    3 => ["handler1", ["id"]],
    4 => ["handler2", ["name"]],
]

1是因為排除第一個匹配
3是因為第一個路由有兩個占位符
4是因為第二個路由有一個占位符

上面的數組,我們可以注冊的methodToRegexToRoutesMap這個量形成的,我是這么寫的

$regexes = array_keys($this->methodToRegexToRoutesMap[$httpMethod]);
foreach ($regexes as $regex) {
    $routeLookup[$index] = [
        $this->methodToRegexToRoutesMap[$httpMethod][$regex]->handler,
        $this->methodToRegexToRoutesMap[$httpMethod][$regex]->variables,
    ];
    $index += count($this->methodToRegexToRoutesMap[$httpMethod][$regex]->variables);
}
最后

調用回調函數,返回一個數組,第一個值用來判斷最終有沒有找到

實現 Route.php類
httpMethod = $httpMethod;
        $this->handler = $handler;
        $this->regex = $regex;
        $this->variables = $variables;
    }

    /**
     * Tests whether this route matches the given string.
     *
     * @param string $str
     *
     * @return bool
     */
    public function matches($str) {
        $regex = "~^" . $this->regex . "$~";
        return (bool) preg_match($regex, $str);
    }

}
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($httpMethod, $routeData, $handler);
            } else {
                $this->addVariableRoute($httpMethod, $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);
    }

    /**
     * 分發
     * @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 = [];
        $index = 1;
        $regexes = array_keys($this->methodToRegexToRoutesMap[$httpMethod]);
        foreach ($regexes as $regex) {
            $routeLookup[$index] = [
                $this->methodToRegexToRoutesMap[$httpMethod][$regex]->handler,
                $this->methodToRegexToRoutesMap[$httpMethod][$regex]->variables,
            ];
            $index += count($this->methodToRegexToRoutesMap[$httpMethod][$regex]->variables);
        }
        $regexCombined = "~^(?:" . implode("|", $regexes) . ")$~";
        if(!preg_match($regexCombined, $uri, $matches)) {
            return [self::NOT_FOUND];
        }
        for ($i = 1; "" === $matches[$i]; ++$i);
        list($handler, $varNames) = $routeLookup[$i];
        $vars = [];
        foreach ($varNames as $varName) {
            $vars[$varName] = $matches[$i++];
        }
        return [self::FOUND, $handler, $vars];
    }
}
配置 nginx.conf重寫到index.php
location / {
        try_files $uri $uri/ /index.php$is_args$args;

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        location ~ .php$ {
            fastcgi_pass   127.0.0.1:9000;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
            include        fastcgi_params;
        }

    }
composer.json自動載入
{
    "name": "salmander/route",
    "require": {},
    "autoload": {
      "psr-4": {
        "SalamanderRoute": "SalamanderRoute/"
      }
  }
}
最終使用 index.php
get("/", function () {
    echo "hello world";
});

$dispatcher->get("/user/{id}", function ($args) {
    echo "user {$args["id"]} visit";
});

// Fetch method and URI from somewhere
$httpMethod = $_SERVER["REQUEST_METHOD"];
$uri = $_SERVER["REQUEST_URI"];

// 去掉查詢字符串
if (false !== $pos = strpos($uri, "?")) {
    $uri = substr($uri, 0, $pos);
}

$routeInfo = $dispatcher->dispatch($httpMethod, $uri);
switch ($routeInfo[0]) {
    case Dispatcher::NOT_FOUND:
        echo "404 not found";
        break;
    case Dispatcher::FOUND:
        $handler = $routeInfo[1];
        $vars = $routeInfo[2];
        $handler($vars);
        break;
}

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/26079.html

相關文章

  • Just for fun——PHP框架簡單由器(2)

    改進 緊接上一篇文章Just for fun——PHP框架之簡單的路由器(1)。代碼下載 效率不高原因 對于以下合并的正則 ~^(?: /user/([^/]+)/(d+) | /user/(d+) | /user/([^/]+) )$~x 最終匹配的是分組中的某一個,我們需要的子匹配也是那個分組中的,然而從結果看 preg_match($regex, /user/niki...

    tomato 評論0 收藏0
  • Just for fun——基于Swoole做個小框架

    摘要:使開發人員可以編寫高性能的異步并發,服務。使用作為網絡通信框架,可以使企業研發團隊的效率大大提升,更加專注于開發創新產品。總之,這個庫讓可以常駐內存,并提供了,等功能。 swoole 使 PHP 開發人員可以編寫高性能的異步并發 TCP、UDP、Unix Socket、HTTP,WebSocket 服務。Swoole 可以廣泛應用于互聯網、移動通信、企業軟件、云計算、網絡游戲、物聯網(...

    CoreDump 評論0 收藏0
  • Just for fun——基于Swoole做個小框架

    摘要:使開發人員可以編寫高性能的異步并發,服務。使用作為網絡通信框架,可以使企業研發團隊的效率大大提升,更加專注于開發創新產品。總之,這個庫讓可以常駐內存,并提供了,等功能。 swoole 使 PHP 開發人員可以編寫高性能的異步并發 TCP、UDP、Unix Socket、HTTP,WebSocket 服務。Swoole 可以廣泛應用于互聯網、移動通信、企業軟件、云計算、網絡游戲、物聯網(...

    fevin 評論0 收藏0
  • Just for fun——PHP框架簡單模板引擎

    摘要:原理使用模板引擎的好處是數據和視圖分離。對于循環語句怎么辦呢這個的話,請看流程控制的替代語法 原理 使用模板引擎的好處是數據和視圖分離。一個簡單的PHP模板引擎原理是 extract數組($data),使key對應的變量可以在此作用域起效 打開輸出控制緩沖(ob_start) include模板文件,include遇到html的內容會輸出,但是因為打開了緩沖,內容輸出到了緩沖中 ob...

    X1nFLY 評論0 收藏0
  • Just for fun——Slim借力Swoole

    摘要:的話,是一個遵循規范微型的框架,作者這樣說大致意思的核心工作分發了請求,然后調用回調函數,返回一個對象。執行的方法時,我們從中取出的依賴,這時候,注冊的回調函數被調用,返回實例。 Slim Slim的話,是一個遵循PSR (PSR-7)規范微型的框架,作者這樣說: Slim is a PHP micro framework that helps you quickly write si...

    leejan97 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<