代码之家  ›  专栏  ›  技术社区  ›  Mez

PHP应用程序URL路由

  •  17
  • Mez  · 技术社区  · 16 年前

    因此,我正在编写一个框架,我希望以此为基础开发一些我正在开发的应用程序(框架就在那里,所以我有一个可以使用的环境,以及一个允许我使用单一登录的系统)。

    我想让这个框架和它拥有的应用程序使用面向资源的体系结构。

    现在,我想创建一个URL路由类,它可以由应用程序编写者(也可能由CMS应用程序用户扩展,但这是未来的发展方向)进行扩展,我正在尝试通过查看其他应用程序如何做到这一点来找出最好的方法。

    8 回复  |  直到 7 年前
        1
  •  13
  •   meda    10 年前

    我喜欢使用Reg-Ex而不是自己制作格式,因为这是常识。我写了一个小类,我使用它可以嵌套这些reg-ex路由表。我曾经使用类似于继承实现的东西,但它不需要继承,所以我重写了它。

    我在一个键上做一个注册表项,并映射到我自己的控制字符串。以下面的例子为例。我访问 /api/related/joe 我的Router类创建了一个新对象 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",
        ));
    }
    

    此外,您还可以为右侧的路由字符串定义所需的默认值。别忘了把它们记录下来,否则你会把人弄糊涂的。如果右边没有包含函数名,我现在正在调用索引。 Here 是我的当前代码。您可能希望更改它以处理您喜欢的错误和/或默认操作。

        2
  •  2
  •       15 年前

    还有另一个框架?不管怎样…

    路由的诀窍是把它全部传递给路由控制器。

    你可能想使用类似我在这里记录的东西:

    http://www.hm2k.com/posts/friendly-urls

    第二个解决方案允许您使用类似于Zend框架的URL。

        3
  •  1
  •   Mez    16 年前

    使用regexs列表来匹配我应该使用的对象

    例如

    ^/users/[\w-]+/bookmarks/(.+)/$
    ^/users/[\w-]+/bookmarks/$
    ^/users/[\w-]+/$
    

    优点:又好又简单,让我直接定义路线 缺点:必须订购,不容易添加新内容(非常容易出错)

    这是,阿法克,姜戈是怎么做到的

        4
  •  0
  •   Unlabeled Meat    16 年前

    我认为很多框架都使用Apache的mod-rewrite和前端控制器的组合。使用mod_rewrite,您可以将这样的URL:/people/get/3转换为: 索引?controller=people&method=get&id=3。php将实现前端控制器,它根据给定的参数路由页面请求。

        5
  •  0
  •   Littm JessicaParker    12 年前

    如你所料,有很多方法可以做到。

    例如,在 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合作,我确实有一个路由器的例子,它是我为一家公司创建的框架的一部分:

    路由引擎基于regex(类似于@gradbot's one),但有一个双向对话,因此如果您的客户机不能在他或她的服务器上运行mod ou rewrite(在apache中)或添加rewrite规则,他或她仍然可以使用带有查询字符串的传统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框架的写作风格-非常简单和好看的代码。

    但是,如果您希望使用它开发复杂的站点,我认为regex是解决方案。

    祝你好运!:)

        6
  •  0
  •   c9s    10 年前

    你应该检查一下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);
    
        7
  •  -1
  •   Michael Johnson    16 年前

    Zend的MVC框架默认使用类似

    /router/controller/action/key1/value1/key2/value2
    

    哪里 router 路由器文件(通过 mod_rewrite , controller 来自由派生自的类定义的控制器操作处理程序 Zend_Controller_Action action 引用控制器中名为 actionAction . 键/值对可以按任意顺序排列,并且可以作为关联数组提供给动作方法。

    我以前在自己的代码中使用过类似的东西,到目前为止它工作得相当好。

        8
  •  -4
  •   mike    16 年前

    试着看看 MVC 模式。
    Zend框架使用它,比如cakephp、codeigner等等。

    我个人不喜欢MVC模型,但大多数时候它是作为“Web视图”组件实现的。

    决定很大程度上取决于偏好…