本文首發於 MVC 框架中的路由器(Router)是如何跑起來的,轉載請註明出處。
說明: 貌似 SF 譯文類別出 BUG,所以本文以原創類別給出。
MVC 路由器(Router)或分發器(Dispatcher)會檢測 HTTP 請求的 URL,並嘗試將單個 URL 元件與控制器和控制器中定義的方法匹配,同時將所有引數傳入方法中。
下面給出了一個簡單的路由器類,可以大致闡明路由器是如何工作的。然而在實際專案中,路由器要比下面的示例路由器複雜很多,因為它必須處理更多的東西。
<?php
class SimpleRouter
{
// 路由陣列,儲存我們定義的路由
private $routes;
// 這個方法用於將定義的路由加入到 $routes 陣列
function add_route($route, callback $closure)
{
$this->routes[$route] = $closure;
}
// 執行特定的路由
function execute()
{
$path = $_SERVER['PATH_INFO'];
/**
* 檢測給定路由是否被定義,
* 或者執行預設的 '/' 首頁路由。
*/
if (array_key_exists($path, $this->route)) {
$this->route[$path]();
} else {
$this->route['/]();
}
}
}
SimpleRouter 類是 MVC 路由器的簡化模型。它的主要功能是將使用者定義的每個路由新增到陣列中,並執行它。要理解它是如何工作的,請將下面的程式碼複製到 index.php 檔案中。
<?php
// index.php
class SimpleRouter
{
// 路由陣列,儲存我們定義的路由
private $routes;
// 這個方法用於將定義的路由加入到 $routes 陣列
function add_route($route, callback $closure)
{
$this->routes[$route] = $closure;
}
// 執行特定的路由
function execute()
{
$path = $_SERVER['PATH_INFO'];
/**
* 檢測給定路由是否被定義,
* 或者執行預設的 '/' 首頁路由。
*/
if (array_key_exists($path, $this->route)) {
$this->route[$path]();
} else {
$this->route['/]();
}
}
}
/* 建立 Router 例項 */
$router = new SimpleRouter();
/* 新增首頁閉包值路由器 */
$router->add_route('/', function(){
echo 'Hello World';
});
/* 新增另一個閉包路由 */
$router->add_route('/greetings', function(){
echo 'Greetings, my fellow men.';
});
/* 新增可回撥函式作為路由 */
$router->add_route('/callback', 'myFunction');
/* 回撥函式處理程式 */
function myFunction(){
echo "This is a callback function named '" . __FUNCTION__ ."'";
}
/* 執行路由 */
$router->execute();
現在到瀏覽器訪問下列 url:
http://localhost/index.php/
http://localhost/index.php/greetings
http://localhost/index.php/callback
對於每個 url,你應該會看到在我們的路由中定義的不同訊息。那麼路由器是如何工作的呢?
在我們的示例中,add_route 方法將 url 的路徑名(route)新增到路由陣列,並且定義對應的處理操作。這個處理操作可以是一個簡單的函式或者回撥函式,作為閉包傳入。現在當我們執行路由器的 execute 方法時,它會檢測在當前 $routes 陣列中是否匹配到路由,如果有,則執行這個函式或回撥函式。
如果你使用 var_dump 這個 $routes 陣列,你可以看到陣列的具體內容。對於每個定義的路由都儲存一個閉包與其關聯。
array (size=3)
'/' =>
object(Closure)[2]
'/greetings' =>
object(Closure)[3]
'/callback' => string 'myFunction' (length=10)
執行處理由以下幾行完成。$this->routes[$path]** 語句返回一個閉包,該閉包儲存在 **\$routes 陣列中,用於指定路由的執行,注意語句結尾處的 ()。
$this->routes[$path]();
// 或
$this->routes['/']();
上面的示例簡單地演示了路由器的工作原理,為了簡單起見,我們沒有處理任何錯誤,也沒有考慮路由的安全性問題。