所以我正在编写一个框架,我想在这个框架上构建一些我正在开发的应用程序(框架在那里,所以我有一个可以使用的环境,以及一个可以让我使用单个登录)
我想制作这个框架,它拥有的应用程序使用面向资源的架构。
现在,我想创建一个 URL 路由类,可由 APP 编写者(也可能由 CMS App 用户扩展,但这是未来的 WAYYYY),我试图通过查看找出最好的方法来做到这一点其他应用程序是如何做到的。
所以我正在编写一个框架,我想在这个框架上构建一些我正在开发的应用程序(框架在那里,所以我有一个可以使用的环境,以及一个可以让我使用单个登录)
我想制作这个框架,它拥有的应用程序使用面向资源的架构。
现在,我想创建一个 URL 路由类,可由 APP 编写者(也可能由 CMS App 用户扩展,但这是未来的 WAYYYY),我试图通过查看找出最好的方法来做到这一点其他应用程序是如何做到的。
我更喜欢使用 reg ex 而不是制作自己的格式,因为这是常识。我写了一个我使用的小类,它允许我嵌套这些 reg ex 路由表。我曾经使用通过继承实现的类似东西,但它不需要继承,所以我重写了它。
我在一个键上做一个 reg ex 并映射到我自己的控制字符串。以下面的例子为例。我访问/api/related/joe
了,我的路由器类创建了一个新对象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",
));
}
您还可以在右侧为您的路由字符串定义您想要的任何默认值。只是不要忘记记录它们,否则你会混淆人们。如果您没有在右侧包含函数名称,我目前正在调用 index 。这是我当前的代码。您可能希望更改它以处理您喜欢的错误和/或默认操作。
又一个框架? - 反正...
路由的诀窍是将其全部传递给您的路由控制器。
您可能想要使用类似于我在此处记录的内容:
http://www.hm2k.com/posts/friendly-urls
第二种解决方案允许您使用类似于 Zend Framework 的 URL。
使用正则表达式列表来匹配我应该使用的对象
例如
^/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 等)获取一个方法,并将路由作为第一个参数,将回调作为第二个参数。
路由可以获得令牌——这是“变量”,它会在运行时根据一些数据(例如成员名称、文章 ID、组织位置名称或其他任何东西——你知道,就像在每个路由控制器中一样)发生变化。
就个人而言,我确实喜欢这种方式,但我认为它对于高级框架来说不够灵活。
由于我目前正在与 ZF 和 Yii 合作,因此我确实有一个路由器示例,它是我为我正在工作的公司创建的一个框架的一部分:
路由引擎基于正则表达式(类似于@gradbot 的),但有双向对话,因此如果您的客户端无法运行 mod_rewrite(在 Apache 中)或在他或她的服务器上添加重写规则,他或她仍然可以使用带有查询字符串的传统 URL。
该文件包含一个数组,其中的每一项,每一项都类似于此示例:
$_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 框架的写作风格 - 非常简单且美观的代码。
但是,如果您希望使用它开发复杂的网站,我认为正则表达式是解决方案。
祝你好运!:)
您应该查看 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
。键/值对可以按任何顺序排列并且可用于动作方法作为关联数组。
我过去在自己的代码中使用过类似的东西,到目前为止它运行得相当好。
尝试看看MVC模式。
Zend Framework 使用它,例如 CakePHP、CodeIgniter、...
我个人不喜欢 MVC 模型,但它大部分时间都是作为“Web 视图”组件实现的。
这个决定很大程度上取决于偏好......