以前使用dispatch, 可是从4.0到如今的8.0 API变更比较大,特别是在最近两次大的版本的升级,为了保持代码简洁丢失了向下兼容的特性。javascript
感受做者的的核心思想不是很坚决。因此生出了本身造轮子的冲动。php
这个是一个微型的能够在openresty里面运行的路由控制器,曾经帮做者作了一次重大改版,如今仍是这个项目第二贡献者。java
其中的思想是很值得借鉴的:jquery
使用树形结构来保存url和handler的映射关系。(按照树形结构查找保证了查找回调函数的效率Olog(n),而传统的以正则表达式作key映射handler方式,查找回调函数时间不稳定,最坏状况须要执行一遍全部的正则表达式)git
将reqest method定义成是match函数的一个封装形式。便于提供方便的形式来映射路由。github
鉴于以上两个很是好的特性,因此就把这个lua的库在PHP下面重写了一遍。同时在写的过程当中加入了一些新的特性:正则表达式
增长error这个API,一个API提供两种调用方式(这个借鉴了dispatch里面的一些特性,有点像jquery的某些方法),能够兼具定义error handler和触发error handler的做用。json
增长hook API,一样有两种调用方式。数组
默认触发“before”和“after”两个hook。分别在执行真正的handler先后。app
在“before”这个hook后面执行用户自定义的hook,这些hook是在定义回调函数的时候一块儿给定当前url须要调用的hook列表。(固然这些hook所有都要用户本身定义回调函数)
这个微型的路由控制器已经提交到packagist网站,能够经过composer工具安装
composer require lloydzhou/router
(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();
使用树形结构来保存url和handler的映射关系。查找URL映射函数的时候保证了查找回调函数的效率O(log n)。
而传统的以正则表达式作key映射handler方式,查找回调函数时间不稳定,最坏状况须要执行一遍全部的正则表达式。
支持编译,将映射好的树形路由映射数组直接编译成源码。不须要每次PHP请求的时候从新切割pathinfo再来生成树形节点。以节省时间!
为了一边测试,一边完善这个库。因此使用这个库结合另一个ActiveRecord和MicroTpl 写了一个简单的博客,里面基本涵盖了这几个库的API。