【问题标题】:PHP Application URL RoutingPHP 应用程序 URL 路由
【发布时间】:2010-09-12 15:29:21
【问题描述】:

所以我正在编写一个框架,我想在这个框架上建立一些我正在开发的应用程序(该框架在那里,所以我有一个可以使用的环境,以及一个可以让我,例如,使用单点登录)

我想制作这个框架,它拥有的应用程序使用面向资源的架构。

现在,我想创建一个 URL 路由类,可由 APP 编写者(也可能由 CMS App 用户扩展,但这是未来的 WAYYYY),我正在尝试找出最好的方法来做到这一点看看其他应用是如何做到的。

【问题讨论】:

    标签: php url routing url-routing


    【解决方案1】:

    使用正则表达式列表来匹配我应该使用的对象

    例如

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

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

    这就是,afaik,Django 是如何做到的

    【讨论】:

      【解决方案2】:

      尝试查看MVC 模式。
      Zend Framework 使用它,例如 CakePHP、CodeIgniter、...

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

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

      【讨论】:

      • 我正在使用 MVC 的东西。我说的是技术方面或 URL 路由。这不是我的问题的答案
      【解决方案3】:

      我认为很多框架结合使用 Apache 的 mod_rewrite 和前端控制器。使用 mod_rewrite,您可以将这样的 URL:/people/get/3 变成这样: index.php?controller=people&method=get&id=3。 Index.php 将实现您的前端控制器,该控制器根据给定的参数路由页面请求。

      【讨论】:

      • 那么,显然忽略您的非 ROA 网址,这与我上面的答案相同,但使用带有特定规则的 mod_rewrite,并通过特定参数而不是通过代码进行“路由”?跨度>
      【解决方案4】:

      Zend 的 MVC 框架默认使用类似的结构

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

      其中router 是路由器文件(通过mod_rewrite 映射,controller 来自控制器操作处理程序,该处理程序由派生自Zend_Controller_Action 的类定义,action 引用控制器中的方法,命名为actionAction。键/值对可以按任何顺序排列,并可作为关联数组用于操作方法。

      我过去在自己的代码中使用过类似的东西,到目前为止效果还不错。

      【讨论】:

      • 操作不适用于 ROA 系统,仅适用于 RPC 样式系统
      • 你说得对……我误读了这个问题。那个,ROA让我失望了。我一直称它为 REST。
      • 这根本不是 RESTFul。仅作记录。
      【解决方案5】:

      我更喜欢使用 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 。 Here 是我当前的代码。您可能希望更改它以处理您喜欢的错误和/或默认操作。

      【讨论】:

      • 第二个例子是我真正想做的事情......(RoR风格) - 我会看看你的代码。
      • 与 Django Python 非常相似。
      【解决方案6】:

      又一个框架? ——不管怎样……

      路由的诀窍是将其全部传递给您的路由控制器。

      您可能想要使用类似于我在此处记录的内容:

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

      第二种解决方案允许您使用类似于 Zend Framework 的 URL。

      【讨论】:

      • 建立一个工作框架是一种启蒙仪式。每个php程序员都必须这样做。
      【解决方案7】:

      正如您所料,有很多方法可以做到这一点。

      例如,在 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 框架的写作风格 - 非常简单且美观的代码。

      但是,如果您想使用它开发复杂的网站,我认为正则表达式是解决方案。

      祝你好运! :)

      【讨论】:

        【解决方案8】:

        你应该看看 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);
        

        【讨论】:

        • 可以添加 404 的路由吗?
        猜你喜欢
        • 1970-01-01
        • 2018-05-03
        • 2014-05-06
        • 1970-01-01
        • 2015-01-12
        • 2020-09-05
        • 2020-01-01
        • 2014-09-30
        • 2020-02-08
        相关资源
        最近更新 更多