【问题标题】:How to handle pluralisation in PHP如何在 PHP 中处理复数
【发布时间】:2016-08-28 22:50:13
【问题描述】:

我有一个应用程序,大概是一个 API,我正在开发它。应用程序以 JSON 格式返回请求的资源。所以我有一个项目管理应用程序,其结构类似于以下内容:

  • 项目
    • 付款
    • 问题
      • 讨论
  • 用户

现在 API 将调用:

/projects                List all the projects
/project                 List all the projects (alias)
/projects/ID/issues      List all the issues of this project
/project/ID/issues       List all the issues of this project (alias)
/projects/ID/issue       List all the issues of this project (alias)
/project/ID/issue        List all the issues of this project (alias)

等等。现在我的问题是,我会为此使用switch ($request),而我有如下疯狂的case 语句:

<?php
  switch ($request) {
    case '/projects':
    case '/project':
      # code...
      break;

    case '/projects/ID/issues':
    case '/project/ID/issues':
    case '/projects/ID/issue':
    case '/project/ID/issue':
      # code...
      break;
  }

我希望你能理解这个问题。想想discussion 部分的案例数量。它会成倍增加。这将通过 3 值的组合来实现,这将达到 2 的幂 3 (23) 出现在 8 case 语句附近。

有没有最好的方法来减少这种情况?这是我第一次在 Stack Overflow。提前致谢。

【问题讨论】:

  • 您主要想要哪种类型?
  • @PraveenKumar 我希望用户提供单数版本。
  • 你在使用框架吗?
  • @MonkeyZeus 不,我没有使用框架。我想让它尽可能简单。
  • 你期望多少个参数。

标签: php pluralize


【解决方案1】:

定义路线

我建议使用preg_match 来处理这类事情。 首先创建一个数组,以路由名称作为键,正则表达式作为值:

$routes = [
    'projects' => '/\/projects?$/',
    'payments' => '/\/projects?\/([0-9]+)\/payments?$/',
    'issues' => '/\/projects?\/([0-9]+)\/issues?$/',
    'discussions' => '/\/projects?\/([0-9]+)\/issues?\/([0-9]+)\/discussions?$/',
    'users' => '/\/users?$/
];

现在检查哪个路由与您的 url 匹配:

function getRoute($url, $routes) {
    foreach ($routes as $name => $regex) {
        if (preg_match($regex, $url)) {
            return $name;
        }
    }

    // return false, or throw an exception if no route has been found
}

现在您可以在交换机中简单地通过路由名称:

switch (getRoute($request, $routes)) {
    case 'projects':
        ...
    case 'payments':
        ...
    case 'issues':
        ...
    case 'discussions':
        ...
    case 'users':
        ...
}

我相信这是您尝试做的最优雅的解决方案。如果您愿意,您可以轻松地将路由数组导出到外部配置。您还避免了对 url 的任何修改。

获取参数(id)

你可以扩展getRoute函数,不仅返回路由名称,还返回参数:

function getRoute($url, $routes) {
    foreach ($routes as $name => $regex) {
        if (preg_match($regex, $url, $matches) {
            // removes the first match which is the whole url
            array_shift($matches);

            return ['route' => $name, 'params' => $matches];
        }
    }
}

上面将返回一个包含匹配路由名称及其参数的数组。这是一个例子:

$route = getRoute('/project/13/issues/14/discussions', $routes);

// $route = [
//     'route' => 'discussions', 
//     'params' => [0 => '13', 1 => '14']
// ];

别忘了把你的 switch 语句改成:

$route = getRoute($request, $routes);

switch($route['route']) {
    ...
}

如果您需要任何进一步的解释,请告诉我。

【讨论】:

  • 我喜欢这个想法,但我会通过传回 id 部分的匹配值来扩展它
  • 这绝对是最好的答案
【解决方案2】:

与 Praveen Kumars 类似的方法是逐部分解析请求并相应地处理它们。你可以使用$requestParts = explode('/',$request); 拆分它然后你去:

if (($requestParts[0]=='project')||($requestParts[0]=='projects')) {
    handleProjectRequest($requestParts);
}
elseif (($requestParts[0]=='user')||($requestParts[0]=='users')) {
    handleUserRequest($requestParts);
}
//...and so on...

您的子函数可能如下所示:

function handleProjectRequest(&$requestParts) {
    if ($requestParts[1]=='ID') { //seems to be the only case?
        if (($requestParts[2]=='issue')||($requestParts[2]=='issues')) {
            //do your magic
        }
    }
}

这将帮助您摆脱那个巨大的 switch 语句,并且还可以很好地组织您的代码。

以一种高级方式,您可以为数组中的每个案例定义复数和单数形式,如下所示:$projectRequests=['project,projects']; 并稍后检查它们:

if (in_array($requestParts[0],$projectRequests)) {
    handleProjectRequest($requestParts);
}

这种方法的优点是,您可以集中定义每个请求的所有可能部分。

【讨论】:

  • 反对者,请解释原因。我明白了,毫无疑问,有更好的答案。但恕我直言,我写的没有错,也回答了这个问题。所以请告诉我我的错误在哪里,以便我改进。谢谢!
【解决方案3】:

您可以通过签入第一次尝试来减少它。即,检查复数或单数形式,并将其替换为一种形式。

<?php
  $request = replace(array("projects", "project"), "project", $request);
  $request = replace(array("issues", "issue"), "issue", $request);
  $request = replace(array("users", "user"), "user", $request);
  $request = replace(array("discussions", "discussion"), "discussion", $request);

稍后检查 switch () 的情况是否只是单数形式:

<?php
  switch ($request) {
    case '/project':
      # code...
      break;

    case '/project/ID/issue':
      # code...
      break;
  }

我知道这将是一个重复的任务,但我想如果你不想使用任何复数方法,这会更好。希望这个“快速破解”会有所帮助。由于您没有超过三个或四个变量,因此这样会更好。

注意:我给出这个答案的主要原因是为了简单而不是使用 RegEx。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-06-12
    • 1970-01-01
    • 1970-01-01
    • 2011-01-02
    • 2012-04-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多