REGEXless диспетчер


Я недавно помог товарищ Сойфер, чтобы ответить на его вопрос здесь: маршрутизация в мой PHP фреймворка

Тогда я подумал

Эй, почему бы не улучшить этот код и поставьте в мою библиотеку фрагментов.

Вот что я придумал:

/**
 * @author Gajus Kuizinas <g.kuizinas@anuary.com>
 * @copyright Anuary Ltd, http://anuary.com
 * @version 1.0.3 (2011 12 07)
 * @param array $routes e.g., array('page/:id' => array('controller' => 'page', 'parameters' => array('id' => 1)));
 */
function ay_dispatcher($url, $routes)
{
    $url            = array
    (
        'original'  => $url,
        'path'      => explode('/', parse_url($url, PHP_URL_PATH))
    );

    $url['length']  = count($url['path']);

    foreach($routes as $filter => $data)
    {
        // reset the parameters every time in case there is partial match
        $parameters     = array();

        $filter         = array
        (
            'original'  => $filter,
            'path'      => explode('/', $filter)
        );

        $filter['length']   = count($filter['path']);

        // this filter is irrelevent
        if($url['length'] <> $filter['length'])
        {
            continue;
        }

        foreach($filter['path'] as $i => $key)
        {
            if(strpos($key, ':') === 0)
            {
                $parameters[substr($key, 1)]    = $url['path'][$i];
            }
            // this filter is irrelevent
            else if($key != $url['path'][$i])
            {       
                continue 2;
            }
        }

        if(!array_key_exists('parameters', $data))
        {
            $data['parameters'] = array();
        }

        $data['parameters'] = array_merge($data['parameters'], $parameters);

        return $data;
    }

    return FALSE;
}

В 1.0.2 версии https://gist.github.com/68bcb1e087237bde76ea.

Я бы хотел услышать комментарии на логику кода. Это, безусловно, лучше с точки зрения производительности, чем любое регулярное выражение диспетчером. Я хоть и забудьте любой основных функций?



609
3
задан 7 декабря 2011 в 04:12 Источник Поделиться
Комментарии
2 ответа

Исходный индекс никогда не используется и в настоящее время можно убрать из URL и фильтра.

Использование временных переменных на самом деле делает код труднее читать.


  1. Замените длина индексы, которые являются только временные значения для проверки. Я называю это pathCount в приведенном ниже коде.

  2. Заменить параметры и слияние, что делать с постоянно добавлять в массив. При добавлении в массив перезаписать существующие значения эквивалентно операции array_merge.

Я хотел бы также изменить имя $ключ к чему-то еще, так как меня смущает это ключ массива. (Я бы назвал это $компонент или что-то подобное). Я не сделать это изменение в коде ниже.

Редактировать:

На самом деле в дополнение к этому $URL и $фильтр также временные переменные вредит вашему читабельности. Они могут быть заменены на соответствующие точки с:

 $urlPath = explode('/', parse_url($url, PHP_URL_PATH);
$filterPath = explode('/', $filter);

Тогда код будет (не проверял):

function ay_dispatcher($url, $routes)
{
$urlPath = explode('/', parse_url($url, PHP_URL_PATH));

foreach($routes as $filter => $data)
{
$filterPath = explode('/', $filter);

if (count($filterPath) !== $count($urlPath))
{
continue;
}

if(!array_key_exists('parameters', $data))
{
$data['parameters'] = array();
}

foreach($filterPath as $i => $key)
{
if(strpos($key, ':') === 0)
{
$data['parameters'][substr($key, 1)] = $urlPath[$i];
}
// this filter is irrelevent
else if($key !== $urlPath[$i])
{
continue 2;
}
}

return $data;
}

return FALSE;
}

Я не уверен, что ваша логика для подсчета траектории фильтр должен быть счет? Возможно, вам нужна функция для этого в качестве параметров, используемых в фильтре будет эффект рассчитывать?

3
ответ дан 8 декабря 2011 в 07:12 Источник Поделиться

1, я удалить $вернуть переменную в ВСЕ и изменения

...
$return = $data;
break;
}
return $return;

для

...
return $data;
}

return FALSE;

2, используя то же имя переменной в два раза трудно прочесть. Я бы изменила

foreach($routes as $filter => $data)
{
...
$filter = array
(
'original' => $filter,
'path' => explode('/', $filter)
);

для

foreach($routes as $originalFilter => $data)
{
...
$filter = array
(
'original' => $originalFilter,
'path' => explode('/', $originalFilter)
);

Или можно переименовать второй $фильтр к $filterInfo или что-то подобное. То же верно для $URL-адрес переменной.

3, я бы извлечь из состояния с

// this filter is irrelevent
if($url['length'] <> $filter['length']) {
continue;
}

функции, название которой происходит от текст комментария:

function isFilterRelevant($url, $filter) {
if ($url['length'] == $filter['length']) {
return true;
}
return false;
}

...
if (!isFilterRelevant($url, $filter)) {
continue;
}

От Чистый код Роберт С. Мартин, С. 53-54:


Комментарии не как Список Шиндлера. Они не являются “чистым”.
Действительно, комментариев, в лучшем случае, необходимое зло. Если наши программы
языки были достаточно выразительный, или если бы у нас был талант тонко
владеть этими языками, чтобы выразить наши намерения, мы были бы не нужны
комментариев очень много—возможно не на всех.

Правильное использование комментариев, чтобы компенсировать нашу неспособность выразить
себя в коде. Обратите внимание, что я употребил слово провал. Я имел в виду это.
Комментарии всегда неудачи. Мы должны иметь их, потому что мы не можем
всегда выяснить, как выразить себя без них, но их использование
это не повод для праздника.

Локальная переменная также будет делать это.

Из книги рефакторинг: улучшение дизайна существующего кода:


Выражения могут стать очень сложными и трудно читать. В таких
ситуации временные переменные могут быть полезны, чтобы сломать
выражение во что-то более управляемым.

Введение поясняющей переменной является особенно ценным с
условная логика, в которой это полезно сделать каждый пункт
состояние и объяснить, что такое состояние означает с именем Temp.

4, Что означает следующее условие проверки?

if(strpos($key, ':') === 0)

Я догадываюсь, но функция с правильным названием было бы лучше здесь.

1
ответ дан 7 декабря 2011 в 09:12 Источник Поделиться