我要進來了!如何使用 PHP 路由套件 FastRoute 開發小專案?

最近因為工作上的需求,要將一個純 HTML 靜態網站修改成以 PHP 改寫的版本。而因為剛好這個案子有非常多個頁面,未來也是我要進行維護,理所當然的會想要將它做的好看、好管理一點。

但是最近事情比較多,沒多少時間能去學習與除錯主流的 PHP 框架,所以我決定先自己寫一個微框架來完成專案雛型,之中最重要的一個東西就是現在要介紹的 — FastRoute 路由套件。

FastRoute 開源套件

github.com/nikic/FastRoute

先說好,目前我使用 FastRoute 編寫的方式並不是最好的,僅僅是能夠運作罷了。且目前頂多只有用迴圈新增路由,並完全沒有使用到強大的正規表達式,想學怎麼在 FastRoute 用正規表達式的朋友就抱歉了,這篇目前只有紀錄最基礎的靜態用法。

配置環境

一、我在 Windows 上開發網頁程式都是使用 XAMPP 來模擬環境,你可以使用你熟悉的網頁伺服器程式,PHP 盡量選擇目前主流版本。(PHP 7.4)

二、因為 FastRoute 得用 Composer 安裝,所以不管你是 Windows 還是 Linux 系統,請前往 Composer 網站下載並按照配置好這個系統環境。

安裝 FastRoute

一、在 XAMPP 下的 htdocs 內開啟命令提示字元 (終端機 / cmd.exe),並輸入指令初始化 composer 專案。這邊系統會用英文問你一堆問題,回答完後再進行下一步。

composer init

二、初始化完成後,資料夾內會多出一個 composer.json,這時再輸入安裝指令來完成 composer 環境建置。

composer install

三、最後鍵入指令以完成 FastRoute 套件的下載與 autoload.php 生成。

composer require nikic/fast-route

基本用法

首先一定要做的事情,就是依照你使用的網站伺服器架構來設定好 Rewrite 規則,而目前我只知道 Apache 用的 .htaccess 寫法,其他的就等有時間架伺服器來研究或等待留言區有人補充吧!

請在 htdocs 下新增一個 .htaccess 檔案,裡面貼上這段程式碼:

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)$ index.php [L]
</IfModule>

接下來,最簡單、快速入門 FastRoute 就是直接抄 ReadMe 文檔中的 ⇢ 範例程式碼 ⇠,再依照你自己需求來改寫。

一般來說會動到的程式碼只有 $dispatcher 內的 $r->addRoute(‘GET’, ‘/’, ‘index’); 和最後段的 switch 結構,前者都是定義哪些網址要經過路由,基本格式是這樣:

$r->addRoute('GET', '路徑', '標籤名稱');

上面的標籤名稱是我亂取的,反正這就類似一個要在最後面用 switch 來辨識的唯一 ID,只要你能處理好後面資料,這邊取什麼名稱都沒差。

以下面這個我寫的範例來說,我定義了三個路由,分別是首頁 index、關於我們 about、聯繫我們 contect。然後在最後的 printPage 之中用 switch 來辨識 $handler 內的傳值,並載入共用的頁首與頁尾,只有中間的內容區有分別。

基本的用法就是這樣,剩下的應該沒什麼問題了……

<?php
require 'vendor/autoload.php';
$dispatcher = FastRoute\simpleDispatcher(function(FastRoute\RouteCollector $r) {
    // Index
    $r->addRoute('GET', '/', 'index');
    // About
    $r->addRoute('GET', '/about', 'about');
    // Contect
    $r->addRoute('GET', '/contect', 'contect');
});
// Fetch method and URI from somewhere
$httpMethod = $_SERVER['REQUEST_METHOD'];
$uri = $_SERVER['REQUEST_URI'];
// Strip query string (?foo=bar) and decode URI
if (false !== $pos = strpos($uri, '?')) {
    $uri = substr($uri, 0, $pos);
}
$uri = rawurldecode($uri);
$routeInfo = $dispatcher->dispatch($httpMethod, $uri);
switch ($routeInfo[0]) {
    case FastRoute\Dispatcher::NOT_FOUND:
        // ... 404 Not Found
        echo '404';
        break;
    case FastRoute\Dispatcher::METHOD_NOT_ALLOWED:
        $allowedMethods = $routeInfo[1];
        // ... 405 Method Not Allowed
        echo '405';
        break;
    case FastRoute\Dispatcher::FOUND:
        $handler = $routeInfo[1];
        $vars = $routeInfo[2];
        printPage($handler, $vars);
        break;
}
function printPage ($handler, $vars) {
    switch ($handler) {
        // 首頁
        case 'index':
            // 共用頁首
            require 'view/header/default.php';
            // 首頁的主體
            require 'view/body/default.php';
            // 共用頁尾
            require 'view/footer/default.php';
        break;
        case 'about':
            require 'view/header/header.php';
            require 'view/body/about.php';
            require 'view/footer/default.php';
        break;
        case 'contect':
            require 'view/header/default.php';
            require 'view/body/contect.php';
            require 'view/footer/default.php';
        break;
    }
}