web框架思考(1)-基本restful路由实现

By | 2016年1月11日

实现一个web框架需要哪些模块,需要包含什么样的功能,需要怎样分层。。。
针对不同领域开发的框架虽然侧重点会有区别(比如博客有typecho,emlog,开源CMS有wordpress,drupal,还有一些商城系统),但是一些基本的元素还是一致的。
本文简要分析了web框架中restful路由的php实现

由于restful只是一个概念,而对应到具体实现实际上是受相关业务所限的,所以本文描述的restful实现实际上可以理解为形如restful的url。如”http://yoursite/user/1″。

文中实现url请求分发的思想与我们日常使用的路由器分发请求有点像,将请求与定义好的路由表进行匹配,然后分发到对应的业务处理。

一、定义一个路由表routers,其中主要包含两部分:

  1. 固定格式的请求规则
  2. 对用户请求的处理方法
$routers = array( 
    array("name"=>"userlist", "pattern"=>"get /user", "action"=>"User#get"),
    array("name"=>"userinfo", "pattern"=>"get /user/:s", "action"=>"User#getById"),
    array("name"=>"useradd", "pattern"=>"post /user", "action"=>"User#add")
);

以第二条规则为例,“get /user/:s”是用户请求的规则,表示用户使用GET协议请求指定id的user信息,对应的处理方法是名为User的action的getById()方法。

二、实现路由规则匹配

主要使用preg_match方法,利用正则表达式实现

private function checkUrl($method, $str, $pattern) {
    $ma = array();
    $pattern = ltrim(rtrim($pattern, "/"));
    $pattern = "/".str_replace("/", "\/", $pattern)."\/?$/";
    $pattern = str_replace(":s", "([^\/]+)", $pattern);
    if (preg_match($pattern, $str, $ma) > 0) {
        return $ma;
    }
    return null;
}

上面的代码是将一条规则与一个请求的url进行匹配,并返回url中自定义的参数。比如请求为“xxx/user/1”,此方法返回的值为第二个元素为1的数组(第一个元素是匹配到整个字段)。

三、分发到对应的action进行处理

获取匹配到的处理类和方法,然后使用php的反射类ReflectionClass创建实例,调用方法(传入参数)。如果找不到对应的类或者方法返回404错误(自定义)。

private function invoke($action, $params) {
    $acts = explode("#", $action);
    $className = $acts[0]."Action";
    $methodName = $acts[1];
    $actionDir = dirname(__FILE__).DIRECTORY_SEPARATOR."action";
    // 载入action文件
    $classFile = $actionDir.DIRECTORY_SEPARATOR.$className.".php";
    if (! file_exists($classFile)) {
        // 404 error
        echo "404 error, no action found";
        return;
    } else {
        require "$classFile";
        // 使用反射执行方法
        $rc = new ReflectionClass($className);
        if (! $rc->hasMethod($methodName)) {
            // 404 error
            echo "404 error, no method found";
            return;
        } else {
            $instance = $rc->newInstance();
            $method = $rc->getMethod($methodName);
            $method->invokeArgs($instance, $params);
        }
    }
}

这三个步骤就完成了路由分发最主要的功能,本文只讨论了最基本的实现,当然实际情况要复杂的多,比如对路由表的维护,参数验证,返回结果的处理,拦截器等等,在这个基础上都可以进一步实现。

发表评论

电子邮件地址不会被公开。 必填项已用*标注