如何在PHP中处理复数形式

4

我有一个应用程序,可能是一个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;
  }

我希望你明白了问题。考虑讨论部分的情况数量。它将呈指数增长。这将通过组合 3 个值来实现,即 2 的 3 次幂(2³)约为 8 种情况陈述。
有没有最好的方法来减少这个数量?这是我第一次使用 Stack Overflow。提前致谢。

你主要想要哪种类型? - Praveen Kumar Purushothaman
@PraveenKumar 我希望用户提供单数版本。 - Medlin Gracia
你在使用框架吗? - MonkeyZeus
@MonkeyZeus 不,我没有使用框架。我想尽可能保持简单。 - Medlin Gracia
你期望有多少个参数? - Praveen Kumar Purushothaman
@PraveenKumar 仅限这四个:userprojectissuediscussion - Medlin Gracia
3个回答

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语句中简单地进行操作:
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”部分的匹配值。 - cmorrissey
这绝对是最好的答案。 - cmorrissey

1

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

<?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;
  }

我知道这会是一个重复的任务,但如果您不想使用任何复数方法,那么这种方法更好。希望这个“快速技巧”有所帮助。由于您没有超过三到四个变量,因此这种方法更好。
注意:我提供这个答案的主要原因是为了简单和不使用正则表达式。

-1
与Praveen Kumar类似的方法是逐部分解析请求并相应地处理它们。您可以使用$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);
}

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

请问给我点踩的人能否解释一下原因?毫无疑问,还有更好的答案。但是在我看来,我写的并没有错,并且回答了问题。所以请告诉我我的错误在哪里,这样我就可以改进。谢谢! - ahuemmer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接