第五步:實現Dispatcher,解析url
每一個框架都有其內置的庫文件,想要使用的時候,都需要使用include或者是require這兩條命令將庫文件引入進來。
然而,一個框架庫文件是相當多,一下子就使用好幾十條include或者是require不僅費時而且還費力,所以我們可以把這些文件定義在一個數組中,然後只要遍歷這個數組,然後一一require就可以了。
在tp框架中, ThinkPHP\Mode\common.php就是這麼一個文件,這個文件定義了一個二維數組,裏面存放了框架所需要使用的文件。
在我們自己實現的框架中,也新建這麼一個文件:
<?php
return array(
'core'=>array(
LIB_PATH.'Think\App.class.php'
)
);
因此,在我們的Think.class.php這個文件中的:
require LIB_PATH.'Think\App.class.php';就可以直接替換成一條循環語句,用來將主要文件包含進來。
$mode=include MODE_PATH.'common.php';
foreach($mode['core'] as $file){
if(is_file($file)){
include$file;
}
}
因此,現在start函數體爲:
staticfunction start(){
//註冊AUTOLOAD方法
spl_autoload_register('Think\Think::autoload');
//讀取核心類庫
$mode=include MODE_PATH.'common.php';
foreach($mode['core'] as $file){
if(is_file($file)){
include$file;
}
}
App::run();
}
這樣就可以快速地導入我們的框架文件,而不必要去寫autoload這個去自動載入,因爲使用這個自動載入需要解析,會花費比較長的時間。
現在,轉入到我們今天的主題,實現dispatcher這個類。
首先,Think.class.php同一目錄下新建一個Dispatcher.class.php這個文件。因爲在上一步驟中,我們只是簡單地實現url模式,但是卻功能簡單和不安全,因此,我們將解析url的功能,也就是在上一步驟中app類中exec這個函數中的內容轉移到dispatcher這個類中去。將解析功能單獨設計成一個類,好處是相當多,因爲這樣的話,擴展解析功能就比較容易,並且也符合面向對象的設計思想。
<?php
namespace Think;
class Dispatcher{
staticfunction dispatch(){
if(isset($_SERVER['PATH_INFO'])){
$url=$_SERVER['PATH_INFO'];
$str=explode('/',trim($url,'/'));
}
$MOD=ucfirst(!empty($str[0])?$str[0]:'Home');
$CON=ucfirst(!empty($str[1])?$str[1]:'index').'Controller';
$ACT=ucfirst(!empty($str[2])?$str[2]:'index');
define('MODULE_NAME',$MOD);
define('CONTROLLER_NAME',$CON);
define('ACTION_NAME',$ACT);
}
}
在這裏,不同的是將最後的實例化類變成了定義常量。因爲dispatcher這個類的主要功能是解析url,而不是執行url,因此,我們將其定義爲常量。這個,在app中的類就可以使用這三個常量了。並且因爲idpatcher中解析函數dispatch是一個靜態的成員函數,因此我們可以在app::init中運行這個函數,然後再在exec中實例類。
所以當前的app.class.php文件變爲:
<?php
namespace Think;
class App{
staticfunction run(){
//環境初始化
self::init();
self::exec();
}
staticfunction init(){
//解析url
Dispatcher::dispatch();
}
staticfunction exec(){
//MODULE_NAME都是在dispatcher這個類中被定義的。
$namespace=MODULE_NAME.'\\Controller\\';
$class=$namespace.CONTROLLER_NAME;
//與上一步操作一樣,實例化類,並且執行類中的操作
$module=new$class;
$act=ACTION_NAME;
$module->$act();
}
}
在init中需要運行dispatcher這個類,但是包含這個文件的類我們並沒有包含,因此我們需要在最開始我們新建的那個common.php這個文件中引入:
<?php
return array(
'core'=>array(
LIB_PATH.'Think\App.class.php',
LIB_PATH.'Think\Dispatcher.class.php',
)
);
運行效果如下圖: