Как справиться меняется в PHP


У меня есть приложение, предположительно 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 заявления.

Есть ли лучший способ уменьшить это? Это мой первый раз в переполнении стека. Заранее спасибо.
3 4

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;
  }
Я знаю, что это будет повторяющаяся задача, но я думаю, что если вы не хотите использовать какие-либо методы плюрализации, это лучше. Надеюсь, что этот "быстрый хак" будет полезен. Поскольку у вас не более трех-четырех переменных, это лучше.

Примечание: основная причина, по которой я дал этот ответ, - это простота и отсутствие использования регулярных выражений.

Определение маршрутов

Я бы рекомендовал использовать 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.

Выборка параметров (идентификаторов)

Вы можете развернуть функцию 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']) {
    ...
}
Дайте мне знать, если вам понадобятся дальнейшие объяснения.

Аналогичный подход к 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);
}
Преимущество этого подхода состоит в том, что вы можете централизованно определить все возможные части каждого запроса.