一个PHP的微型路由控制器

以前使用dispatch, 可是从4.0到如今的8.0 API变更比较大,特别是在最近两次大的版本的升级,为了保持代码简洁丢失了向下兼容的特性。javascript

感受做者的的核心思想不是很坚决。因此生出了本身造轮子的冲动。php

router.lua

这个是一个微型的能够在openresty里面运行的路由控制器,曾经帮做者作了一次重大改版,如今仍是这个项目第二贡献者。java

其中的思想是很值得借鉴的:jquery

  1. 使用树形结构来保存url和handler的映射关系。(按照树形结构查找保证了查找回调函数的效率Olog(n),而传统的以正则表达式作key映射handler方式,查找回调函数时间不稳定,最坏状况须要执行一遍全部的正则表达式)git

  2. 将reqest method定义成是match函数的一个封装形式。便于提供方便的形式来映射路由。github

Router

鉴于以上两个很是好的特性,因此就把这个lua的库在PHP下面重写了一遍。同时在写的过程当中加入了一些新的特性:正则表达式

  1. 增长error这个API,一个API提供两种调用方式(这个借鉴了dispatch里面的一些特性,有点像jquery的某些方法),能够兼具定义error handler和触发error handler的做用。json

  2. 增长hook API,一样有两种调用方式。数组

  3. 默认触发“before”和“after”两个hook。分别在执行真正的handler先后。app

  4. 在“before”这个hook后面执行用户自定义的hook,这些hook是在定义回调函数的时候一块儿给定当前url须要调用的hook列表。(固然这些hook所有都要用户本身定义回调函数)

安装

这个微型的路由控制器已经提交到packagist网站,能够经过composer工具安装

composer require lloydzhou/router

此处附README里面的一个例子:

(new Router())
/* 定义错误处理函数 */
->error(401, function($message){
    header('Location: /login', true, 302);
    die($message);
})
->error(405, function($message){
    header('Location: /hello/world', true, 302);
})
->error(406, function($message){
    die($message);
})
/* 定义hook函数,除了内置默认调用的before和after,还定义了检查登陆的auth */
->hook('auth', function($params){
    if ('lloyd' == $params['name'])
    return $params;
    $params['router']->error(401, 'Forbiden');
})
/* 定义after这个钩子函数,支持json或者jsonp格式输出 */
->hook('after', function($result, $router){
    if ($result) {
    header('Content-type: application/'. ($_GET['jsoncallback']?'javascript':'json'));
    if ($_GET['jsoncallback'])
        print $_GET['jsoncallback']. '('. json_encode($result). ')';
    else print json_encode($result);
    }
})
->hook('before', function($params){
    //$params['name'] = 'lloydzhou';
    return $params;
})
/* 定义url映射 */
->get('/', function(){
    echo "Hello world !!!";
})
->get('/hello/:name', function($name){
    echo "Hello $name !!!";
})
->get('/hello/:name/again', function($name){
    echo "Hello $name again !!!";
}, 'auth')
->get('/hello/:name.:ext', function($name, $ext){
    if ('js' == $ext || 'json' == $ext) return array('name'=>$name);
    return array('code'=>1, 'msg'=>'error message...');
}, 'auth')
/* 程序入口,以当前的url查找对应的处理函数,并获取变量执行该函数 */
->execute();

启动服务

php -S 0.0.0.0:8888 test.php

测试

curl -vvv 127.0.0.1:8888/hello/
url未能映射成功,触发405错误处理函数, 自动跳转向 URL: "/hello/world"

curl -vvv 127.0.0.1:8888/hello/lloyd 
返回 "Hello lloyd !!!"

curl -vvv 127.0.0.1:8888/hello/lloyd/again 
返回 "Hello lloyd again !!!"

curl -vvv 127.0.0.1:8888/hello/world/again 
在钩子函数auth处理失败触发401错误处理函数, 自动跳转到 URL: "/login"

curl -vvv 127.0.0.1:8888/hello/lloyd.json 
支持“/”和“.”做为pathinfo的分隔符,而且和after钩子函数配合,返回json格式文本 {"name": "lloyd"}

curl -vvv 127.0.0.1:8888/hello/lloyd.js?jsoncallback=test
返回jsonp格式文本 test({"name": "lloyd"})

curl -vvv 127.0.0.1:8888/hello/lloyd.jsx?jsoncallback=test
最后的后缀名不匹配,输出错误jsonp格式的消息 test({"code":1,"msg":"error message..."})

编译

开发环境使用CRouter替代Router能够自动检测文件修改时间,而且编译成原生数组保存至router.inc.php

(new CRouter('router.inc.php', true))

发布的时候只须要把路由映射的部分替换成如下两行代码便可跳过建立路由映射表的阶段。以节省时间!!!

$router = include('router.inc.php');
$router->execute();

性能

  1. 使用树形结构来保存url和handler的映射关系。查找URL映射函数的时候保证了查找回调函数的效率O(log n)。

  2. 而传统的以正则表达式作key映射handler方式,查找回调函数时间不稳定,最坏状况须要执行一遍全部的正则表达式。

  3. 支持编译,将映射好的树形路由映射数组直接编译成源码。不须要每次PHP请求的时候从新切割pathinfo再来生成树形节点。以节省时间!

DEMO

为了一边测试,一边完善这个库。因此使用这个库结合另一个ActiveRecordMicroTpl 写了一个简单的博客,里面基本涵盖了这几个库的API。

相关文章
相关标签/搜索