PHP应用程序URL路由
所以我正在编写一个框架,我要在这个框架上创build一些我正在使用的应用程序(框架就在那里,所以我有一个可以使用的环境,而一个系统可以让我使用一个login)
我想制作这个框架,它的应用程序使用面向资源的架构。
现在,我想要创build一个可由APP编写者扩展的URL路由类(也可能是CMS应用程序的用户,但将来会提前推出),我试图找出最好的方法其他应用程序如何做。
我更喜欢使用reg ex制作自己的格式,因为这是常识。 我写了一个我使用的小类,它允许我嵌套这些注册前路由表。 我使用类似的东西,通过inheritance实现,但它不需要inheritance,所以我重写了它。
我做了一个关键的注册,并映射到我自己的控制string。 以下面的例子。 我访问/api/related/joe
和我的路由器类创build一个新的对象ApiController
并调用它的方法relatedDocuments(array('tags' => 'joe'));
// the 12 strips the subdirectory my app is running in $index = urldecode(substr($_SERVER["REQUEST_URI"], 12)); Route::process($index, array( "#^api/related/(.*)$#Di" => "ApiController/relatedDocuments/tags", "#^thread/(.*)/post$#Di" => "ThreadController/post/title", "#^thread/(.*)/reply$#Di" => "ThreadController/reply/title", "#^thread/(.*)$#Di" => "ThreadController/thread/title", "#^ajax/tag/(.*)/(.*)$#Di" => "TagController/add/id/tags", "#^ajax/reply/(.*)/post$#Di"=> "ThreadController/ajaxPost/id", "#^ajax/reply/(.*)$#Di" => "ArticleController/newReply/id", "#^ajax/toggle/(.*)$#Di" => "ApiController/toggle/toggle", "#^$#Di" => "HomeController", ));
为了保持错误和简单,你可以细分你的表。 这样你可以把路由表放到它所控制的类中。 以上面的例子,你可以将三个线程调用合并为一个。
Route::process($index, array( "#^api/related/(.*)$#Di" => "ApiController/relatedDocuments/tags", "#^thread/(.*)$#Di" => "ThreadController/route/uri", "#^ajax/tag/(.*)/(.*)$#Di" => "TagController/add/id/tags", "#^ajax/reply/(.*)/post$#Di"=> "ThreadController/ajaxPost/id", "#^ajax/reply/(.*)$#Di" => "ArticleController/newReply/id", "#^ajax/toggle/(.*)$#Di" => "ApiController/toggle/toggle", "#^$#Di" => "HomeController", ));
然后你定义ThreadController :: route就像这样。
function route($args) { Route::process($args['uri'], array( "#^(.*)/post$#Di" => "ThreadController/post/title", "#^(.*)/reply$#Di" => "ThreadController/reply/title", "#^(.*)$#Di" => "ThreadController/thread/title", )); }
你也可以在右边为你的路由string定义任何默认值。 只是不要忘了logging他们,否则你会混淆人。 我目前正在调用索引,如果你没有在右侧包括一个函数名称。 这是我目前的代码。 您可能需要将其更改为处理错误的方式和/或默认操作。
又一个框架? – 反正…
诀窍是将路由传递给路由控制器。
你可能会想使用类似于我在这里logging的东西:
http://www.hm2k.com/posts/friendly-urls
第二个解决scheme允许您使用类似于Zend Framework的URL。
使用正则expression式来匹配我应该使用的对象
例如
^/users/[\w-]+/bookmarks/(.+)/$ ^/users/[\w-]+/bookmarks/$ ^/users/[\w-]+/$
优点:好又简单,让我直接定义路由缺点:必须订购,不容易添加新的东西(很容易出错)
这是一个afaik,Django是如何做的
我想很多框架都使用Apache的mod_rewrite和前端控制器的组合。 使用mod_rewrite,你可以把这样的URL变成:/ people / get / 3:index.php?controller = people&method = get&id = 3。 Index.php会实现你的前端控制器,它根据给定的参数路由页面请求。
正如你所料,有很多方法可以做到这一点。
例如,在Slim Framework中 ,路由引擎的一个例子可能是下面的(基于模式${OBJECT}->${REQUEST METHOD}(${PATTERM}, ${CALLBACK})
):
$app->get("/Home", function() { print('Welcome to the home page'); } $app->get('/Profile/:memberName', function($memberName) { print( 'I\'m viewing ' . $memberName . '\'s profile.' ); } $app->post('/ContactUs', function() { print( 'This action will be fired only if a POST request will occure'); }
因此,初始化的实例( $app
)为每个请求方法(例如get,post,put,delete等等)获取一个方法,并获取一个路由作为第一个参数,第二个作为callback。
路由可以获得令牌 – 这是“可变的”,它将在运行时基于某些数据(如成员名称,文章ID,组织位置名称或其他 – 就像在每个路由控制器中一样)而改变。
就我个人而言,我喜欢这种方式,但我认为这对于高级框架来说不够灵活。
由于我目前正在使用ZF和Yii,所以我确实有一个路由器的例子,作为我工作的一个公司的框架的一部分:
路由引擎是基于正则expression式(类似于@ gradbot的),但得到了双向对话,所以如果你的客户端不能运行mod_rewrite(在Apache中)或在他或她的服务器上添加重写规则,他或她仍然可以使用传统的URL与查询string。
该文件包含一个数组,每个数组都与这个例子类似:
$_FURLTEMPLATES['login'] = array( 'i' => array( // Input - how the router parse an incomming path into query string params 'pattern' => '@Members/Login/?@i', 'matches' => array( 'Application' => 'Members', 'Module' => 'Login' ), ), 'o' => array( // Output - how the router parse a query string into a route '@Application=Members(&|&)Module=Login/?@' => 'Members/Login/' ) );
您也可以使用更复杂的组合,例如:
$_FURLTEMPLATES['article'] = array( 'i' => array( 'pattern' => '@CMS/Articles/([\d]+)/?@i', 'matches' => array( 'Application' => "CMS", 'Module' => 'Articles', 'Sector' => 'showArticle', 'ArticleID' => '$1' ), ), 'o' => array( '@Application=CMS(&|&)Module=Articles(&|&)Sector=showArticle(&|&)ArticleID=([\d]+)@' => 'CMS/Articles/$4' ) );
我认为底线是可能性是无止境的,它取决于你希望你的框架有多复杂,以及你想要做什么。
例如,如果只是打算成为一个Web服务或简单的网站封装,那么只要使用Slim框架的写作风格即可,非常简单且好看的代码。
但是,如果你想开发复杂的网站使用它,我认为正则expression式是解决scheme。
祝你好运! 🙂
你应该看看Pux https://github.com/c9s/Pux
这里是大纲
<?php require 'vendor/autoload.php'; // use PCRE patterns you need Pux\PatternCompiler class. use Pux\Executor; class ProductController { public function listAction() { return 'product list'; } public function itemAction($id) { return "product $id"; } } $mux = new Pux\Mux; $mux->any('/product', ['ProductController','listAction']); $mux->get('/product/:id', ['ProductController','itemAction'] , [ 'require' => [ 'id' => '\d+', ], 'default' => [ 'id' => '1', ] ]); $mux->post('/product/:id', ['ProductController','updateAction'] , [ 'require' => [ 'id' => '\d+', ], 'default' => [ 'id' => '1', ] ]); $mux->delete('/product/:id', ['ProductController','deleteAction'] , [ 'require' => [ 'id' => '\d+', ], 'default' => [ 'id' => '1', ] ]); $route = $mux->dispatch('/product/1'); Executor::execute($route);
Zend的MVC框架默认使用类似的结构
/router/controller/action/key1/value1/key2/value2
其中router
是路由器文件(通过mod_rewrite
映射, controller
来自控制器动作处理程序,该动作处理程序由派生自Zend_Controller_Action
的类定义,并且action
引用控制器中的方法,名为actionAction
。键/值对可以以任何顺序并作为关联数组提供给action方法。
我以前在自己的代码中使用过类似的东西,到目前为止它的工作还算不错。
试着看看MVC模式。
Zend框架使用它,但也CakePHP,CodeIgniter,…
我个人不喜欢MVC模型,但大部分时间都是以“View for web”组件实现的。
这个决定很大程度上取决于偏好…