第五步:实现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',
)
);
运行效果如下图: