PHPackages                             karelwintersky/arris.router - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Framework](/categories/framework)
4. /
5. karelwintersky/arris.router

ActiveLibrary[Framework](/categories/framework)

karelwintersky/arris.router
===========================

Arris Application µFramework - AppRouter class

2.3.1(5mo ago)0864[2 issues](https://github.com/ArrisFramework/Arris.AppRouter/issues)MITPHPPHP 8.\*

Since Aug 2Pushed 2d ago1 watchersCompare

[ Source](https://github.com/ArrisFramework/Arris.AppRouter)[ Packagist](https://packagist.org/packages/karelwintersky/arris.router)[ RSS](/packages/karelwintersky-arrisrouter/feed)WikiDiscussions main Synced 2d ago

READMEChangelog (10)Dependencies (2)Versions (33)Used By (0)

Arris.AppRouter (`karelwintersky/arris.router`)
===============================================

[](#arrisapprouter-karelwinterskyarrisrouter)

Статический роутер для Arris µFramework на базе форка [nikic/FastRoute](https://github.com/nikic/FastRoute) v2. Поддерживает группы роутов, middleware (`before`/`after`), обратный роутинг и алиасы плейсхолдеров (BETA).

---

Оглавление
----------

[](#оглавление)

- [Установка](#%D1%83%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0)
- [Быстрый старт](#%D0%B1%D1%8B%D1%81%D1%82%D1%80%D1%8B%D0%B9-%D1%81%D1%82%D0%B0%D1%80%D1%82)
- [Инициализация](#%D0%B8%D0%BD%D0%B8%D1%86%D0%B8%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F)
- [Определение маршрутов](#%D0%BE%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5-%D0%BC%D0%B0%D1%80%D1%88%D1%80%D1%83%D1%82%D0%BE%D0%B2)
- [Группировка маршрутов](#%D0%B3%D1%80%D1%83%D0%BF%D0%BF%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0-%D0%BC%D0%B0%D1%80%D1%88%D1%80%D1%83%D1%82%D0%BE%D0%B2)
- [Middleware](#middleware)
- [Обратный роутинг](#%D0%BE%D0%B1%D1%80%D0%B0%D1%82%D0%BD%D1%8B%D0%B9-%D1%80%D0%BE%D1%83%D1%82%D0%B8%D0%BD%D0%B3)
- [Алиасы параметров (BETA)](#%D0%B0%D0%BB%D0%B8%D0%B0%D1%81%D1%8B-%D0%BF%D0%B0%D1%80%D0%B0%D0%BC%D0%B5%D1%82%D1%80%D0%BE%D0%B2-beta)
- [Обработка исключений](#%D0%BE%D0%B1%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%BA%D0%B0-%D0%B8%D1%81%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%BD%D0%B8%D0%B9)
- [Настройки](#%D0%BD%D0%B0%D1%81%D1%82%D1%80%D0%BE%D0%B9%D0%BA%D0%B8)
- [Отладка](#%D0%BE%D1%82%D0%BB%D0%B0%D0%B4%D0%BA%D0%B0)
- [Примеры](#%D0%BF%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D1%8B)
- [API Reference](#api-reference)
- [Совместимость](#%D1%81%D0%BE%D0%B2%D0%BC%D0%B5%D1%81%D1%82%D0%B8%D0%BC%D0%BE%D1%81%D1%82%D1%8C)

---

Установка
---------

[](#установка)

```
composer require karelwintersky/arris.router
```

Зависимости: PHP `8.*`, `psr/log`. Ядро FastRoute входит в пакет и внешне не требуется.

Быстрый старт
-------------

[](#быстрый-старт)

```
use Arris\AppRouter;
use Arris\Exceptions\{
    AppRouterHandlerError,
    AppRouterMethodNotAllowedException,
    AppRouterNotFoundException
};

AppRouter::init();

AppRouter::get('/', function() { echo 'Главная'; }, 'home');
AppRouter::get('/about', 'AboutController@index', 'about');

try {
    AppRouter::dispatch();
} catch (AppRouterNotFoundException $e) {
    http_response_code(404);
    echo 'Страница не найдена';
} catch (AppRouterMethodNotAllowedException $e) {
    http_response_code(405);
    echo 'Метод не разрешен';
} catch (AppRouterHandlerError $e) {
    http_response_code(500);
    echo 'Ошибка сервера';
}
```

`AppRouter` — статический класс: `init()` считывает `$_SERVER['REQUEST_URI']` и `$_SERVER['REQUEST_METHOD']`напрямую, роуты декларируются вызовами, `dispatch()` выполняет матчинг и вызывает обработчик.

Инициализация
-------------

[](#инициализация)

```
AppRouter::init(
    logger?: Psr\Log\LoggerInterface,  // логгер (по умолчанию NullLogger)
    namespace?: string,                // неймспейс по умолчанию для строковых хэндлеров
    prefix?: string,                   // глобальный префикс URL
    allowEmptyGroups?: bool,           // разрешить пустые группы (false)
    allowEmptyHandlers?: bool,         // разрешить пустые обработчики (false)
    useAliases?: bool,                 // использовать алиасы параметров (false)
    customDataSource?: array            // источник данных запроса, эмулятор $_SERVER (null = $_SERVER)
);
```

`customDataSource` — массив, эмулирующий `$_SERVER` как источник данных запроса: ключи соответствуют `$_SERVER` (`REQUEST_URI`, `REQUEST_METHOD`). По умолчанию `null` → используется `$_SERVER`. Позволяет запускать роутер из CLI и писать тесты без HTTP-суперглобалов:

```
AppRouter::init(
    allowEmptyHandlers: true,
    customDataSource: ['REQUEST_URI' => '/admin/users/', 'REQUEST_METHOD' => 'GET']
);
```

Отсутствующие ключи не роняют `init()`: `REQUEST_URI` → `/`, `REQUEST_METHOD` → `GET`.

```
// через конструктор (те же опции, кроме useAliases)
$router = new AppRouter(logger: $logger, namespace: 'App\Controllers', prefix: '/api/v1');

// через setOption
AppRouter::init();
AppRouter::setOption(AppRouter::OPTION_ALLOW_EMPTY_HANDLERS, true);
AppRouter::setOption(AppRouter::OPTION_DEFAULT_ROUTE, '/404');
```

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

[](#определение-маршрутов)

```
AppRouter::get($route, $handler, $name = null);
AppRouter::post($route, $handler, $name = null);
AppRouter::put($route, $handler, $name = null);
AppRouter::patch($route, $handler, $name = null);
AppRouter::delete($route, $handler, $name = null);
AppRouter::head($route, $handler, $name = null);
AppRouter::options($route, $handler, $name = null);

// все методы сразу
AppRouter::any($route, $handler, $name = null);

// произвольный набор методов
AppRouter::addRoute(['GET', 'POST'], $route, $handler, $name = null);
```

Синтаксис маршрута — FastRoute v2:

- статические части: `/user/list/`
- плейсхолдеры: `/user/{id}` (по умолчанию `[^/]+`), с регуляркой: `/user/{id:\d+}`
- опциональные группы: `/user/{id}[/{action}]`, `/add[/]`
- опциональными могут быть только оконечные группы.

### Форматы обработчика

[](#форматы-обработчика)

ФорматПоведение`function () { ... }`Closure`[ Class::class, 'method' ]`класс инстанциируется (если не зарегистрирован через `addHandler()`), вызывается метод`'Class@method'`тип метода определяется рефлексией; динамический метод → инстанс класса`'Class@'`вызывается `__invoke()` класса`'function_name'`обычная функция`[]`пустой хэндлер: прогоняются только middleware; требует `allowEmptyHandlers: true``null`роут **не регистрируется** — запрос упадёт в `AppRouterNotFoundException` (404)### Именование маршрутов

[](#именование-маршрутов)

```
AppRouter::get('/user/{id}/edit', 'UserController@edit', 'user.edit');
$url = AppRouter::getRouter('user.edit', ['id' => 42]); // => /user/42/edit
```

Группировка маршрутов
---------------------

[](#группировка-маршрутов)

```
AppRouter::group(
    prefix: '/admin',
    namespace: 'App\Controllers\Admin',   // префикс неймспейса для строковых хэндлеров группы
    before: 'AuthMiddleware@check',
    after: 'LogMiddleware@log',
    callback: function () {
        AppRouter::get('/dashboard', 'DashboardController@index'); // => /admin/dashboard
        AppRouter::get('/settings', 'SettingsController@index');
    }
);
```

Сигнатура: `group(prefix='', namespace='', before=null, after=null, callback=null, alias=[])`.

> **Важно:** `callback` — пятый (именованный) параметр. `AppRouter::group('/admin', function () {...})`позиционно передаст замыкание в `$namespace` и вызовет `TypeError`. Всегда используйте именованные аргументы (`callback:`) либо полный позиционный набор.

Группы вкладываются (стек префиксов/неймспейсов/миддлваров). При исключении внутри `callback` стеки восстанавливаются, а исключение уходит дальше по иерархии (обёртка `try/finally`).

```
AppRouter::group('/api', '', null, null, function () {
    AppRouter::group('/v1', '', null, null, function () {
        AppRouter::get('/users', 'Api\V1\UserController@index'); // => /api/v1/users
    });
});
```

Middleware
----------

[](#middleware)

Регистрируются для группы в `before`/`after` и выполняются вокруг обработчика маршрута:

```
AppRouter::group(
    prefix: '/admin',
    before: 'AuthMiddleware@check',
    after: 'LogMiddleware@log',
    callback: function () { /* роуты */ }
);
```

Форматы: строка `'Class@method'`, массив `[Class::class, 'method']`, Closure, имя функции. Метод middleware вызывается с аргументами `($uri, $routeInfo)`.

Порядок выполнения для вложенных групп `GET /admin/users/list`:

```
1. Middleware1::before   (внешняя группа)
2. Middleware2::before   (внутренняя группа)
3. UserController::list  (обработчик)
4. Middleware2::after
5. Middleware1::after

```

Инстансы middleware можно зарегистрировать заранее (имитация контейнера):

```
AppRouter::addHandlerMiddleware(AuthMiddleware::class, new AuthMiddleware());
AppRouter::addHandler(UserController::class, new UserController($db)); // то же для обработчиков
```

Неймспейс для middleware отдельно задавать не нужно — классы передаются с полным именем (FQN).

Обратный роутинг
----------------

[](#обратный-роутинг)

```
AppRouter::get('/blog/{category}/{slug}', 'BlogController@show', 'blog.post');

$url = AppRouter::getRouter('blog.post', ['category' => 'news', 'slug' => 'hello-world']);
// => /blog/news/hello-world
```

- `getRouter('*')` — возвращает массив всех именованных маршрутов.
- `getRouter('')` — значение по умолчанию (по умолчанию `/`, см. `OPTION_DEFAULT_ROUTE`).
- Неизвестное имя — значение по умолчанию.
- Именованные плейсхолдеры (в т.ч. `{name:regex}`) заменяются переданными значениями; не переданные — остаются как есть.
- Оконечный необязательный слэш `[/]` заменяется на обязательный, необязательные группы удаляются.

Значения подставляются без интерпретации (не трактуются как regex-backreference).

Использование в Smarty-шаблонах (требует регистрации класса):

```
$smarty->registerClass('Arris\AppRouter', 'Arris\AppRouter');
```

```
{$post.title}
```

Алиасы параметров (BETA)
------------------------

[](#алиасы-параметров-beta)

Включаются опцией `OPTION_USE_ALIASES`. Алиасы глобальные (задать алиасы только для группы нельзя).

```
AppRouter::setOption(AppRouter::OPTION_USE_ALIASES, true);

AppRouter::addAlias('user_id', '\d+');
AppRouter::addAlias('username', '[a-zA-Z]+');
// или массивом
AppRouter::addAlias([['user_id' => '\d+'], ['username' => '[a-zA-Z]+']]);

AppRouter::get('/user/{user_id}', function ($user_id) {...}, 'user.by_id');
AppRouter::get('/user/{username}', function ($username) {...}, 'user.by_name');
```

При запросе `/user/123/` сработает `user.by_id`, при `/user/wombat/` — `user.by_name`. Без алиасов оба роута раскрываются в `([^/]+)` и конфликтуют (`BadRouteException`). Обратный роутинг для алиасов работает штатно.

Обработка исключений
--------------------

[](#обработка-исключений)

ИсключениеКодСлучай`AppRouterNotFoundException`404маршрут не найден`AppRouterMethodNotAllowedException`405метод не разрешён для маршрута`AppRouterHandlerError`500ошибка обработчика (пустой, несуществующий класс/метод/функция)Все наследуются от `Arris\Exceptions\AppRouterException` (и `RuntimeException`). Кроме `getMessage()` доступны:

```
catch (AppRouterNotFoundException $e) {
    $e->getError();         // строка с описанием и указанием места декларации роута
    $e->getInfo();          // ['request', 'uri', 'method', 'info', 'rule']
    $e->getInfo('uri');     // конкретный ключ
}
```

Настройки
---------

[](#настройки)

```
AppRouter::OPTION_ALLOW_EMPTY_GROUPS      // разрешить пустые группы (default false)
AppRouter::OPTION_ALLOW_EMPTY_HANDLERS    // разрешить пустые хэндлеры [] (default false)
AppRouter::OPTION_DEFAULT_ROUTE           // значение getRouter() для пустых/ненайденных имён (default '/')
AppRouter::OPTION_USE_ALIASES             // включить алиасы параметров (default false)

AppRouter::setOption($name, $value);
```

Замечания:

- `setDefaultNamespace()` и опция `namespace` в `init()`/`group()` — префикс неймспейса только для **строковых** хэндлеров (`'Class@method'`); на массивные `[Class::class, 'method']` не влияют.
- Роуты компилируются (собираются в FastRoute-диспетчер) **при каждом вызове `dispatch()`** — кеш скомпилированных правил не используется.

Отладка
-------

[](#отладка)

```
// все правила маршрутизации (включая backtrace декларации)
$rules = AppRouter::getRoutingRules();

// WEB-таблица
echo \Arris\AppRouter\Helper::dumpRoutingRulesWeb($rules, /*withMiddlewares*/ true);

// CLI-таблица
echo \Arris\AppRouter\Helper::dumpRoutingRulesCLI($rules);

// имя текущего роута, список имён, алиасы
$info     = AppRouter::getRoutingInfo();   // результат последнего dispatch()
$names    = AppRouter::getRoutersNames();
$aliases  = AppRouter::getAliases();
```

Примеры
-------

[](#примеры)

Полный пример приложения:

```
use Arris\AppRouter;
use Arris\Exceptions\{
    AppRouterNotFoundException,
    AppRouterMethodNotAllowedException,
    AppRouterHandlerError
};

class AuthMiddleware {
    public function check($uri, $routeInfo) {
        if (!isset($_SESSION['user_id'])) {
            header('Location: /login');
            exit;
        }
    }
}

AppRouter::init(namespace: 'App\Controllers');

AppRouter::get('/', 'HomeController@index', 'home');
AppRouter::get('/about', 'HomeController@about', 'about');

AppRouter::group(
    prefix: '/auth',
    callback: function () {
        AppRouter::get('/login', 'AuthController@loginForm', 'auth.login');
        AppRouter::post('/login', 'AuthController@login');
    }
);

AppRouter::group(
    prefix: '/user',
    before: 'AuthMiddleware@check',
    callback: function () {
        AppRouter::get('/profile', 'UserController@profile', 'user.profile');
        AppRouter::group(
            prefix: '/posts',
            callback: function () {
                AppRouter::get('/', 'PostController@index', 'user.posts');
                AppRouter::get('/{id}/edit', 'PostController@editForm', 'user.posts.edit');
                AppRouter::post('/{id}/edit', 'PostController@update');
            }
        );
    }
);

try {
    AppRouter::dispatch();
} catch (AppRouterNotFoundException $e) {
    http_response_code(404);
} catch (AppRouterMethodNotAllowedException $e) {
    http_response_code(405);
} catch (AppRouterHandlerError $e) {
    http_response_code(500);
    if (defined('DEBUG') && DEBUG) {
        echo $e->getMessage();
    }
}
```

API Reference
-------------

[](#api-reference)

Основные методы:

МетодОписание`init(...$options)`Инициализация роутера`get/post/put/patch/delete/head/options($route, $handler, $name = null)`Маршруты по методам`any($route, $handler, $name = null)`Маршрут для всех методов`addRoute($httpMethod, $route, $handler, $name = null)`Произвольный(ые) метод(ы)`group($prefix, $namespace, $before, $after, $callback, $alias)`Группа роутов`dispatch()`Матчинг и выполнение текущего запроса`getRouter($name, $parts = [])`Обратный роутингВспомогательные:

МетодОписание`setOption($name, $value)`Установка опции`setDefaultNamespace($namespace)`Неймспейс по умолчанию для строковых хэндлеров`addHandler($name, $instance)`Предрегистрация инстанса обработчика`addHandlerMiddleware($name, $instance)`Предрегистрация инстанса middleware`addAlias($name, $regexp = null)`Добавление алиаса параметра`getRoutingRules()`Все правила маршрутизации`getRoutingInfo()`Результат последнего `dispatch()``getRoutersNames()`Список имён маршрутов`getAliases()`Список алиасовСовместимость
-------------

[](#совместимость)

- PHP `8.*`
- PSR-3 Logger Interface
- FastRoute v2 встроен в пакет; PSR-7 не используется

Лицензия
--------

[](#лицензия)

MIT

###  Health Score

44

—

FairBetter than 90% of packages

Maintenance87

Actively maintained with recent releases

Popularity17

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity55

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~30 days

Recently: every ~51 days

Total

32

Last Release

163d ago

Major Versions

0.9.1 → 1.0.02023-08-07

v1.x-dev → 2.0.02025-03-04

PHP version history (3 changes)0.9PHP &gt;=7.4

1.2.0PHP &gt;=7.4 || 8.\*

2.0.0PHP 8.\*

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/2164874?v=4)[Karel Wintersky](/maintainers/KarelWintersky)[@KarelWintersky](https://github.com/KarelWintersky)

---

Top Contributors

[![KarelWintersky](https://avatars.githubusercontent.com/u/2164874?v=4)](https://github.com/KarelWintersky "KarelWintersky (51 commits)")

---

Tags

middlewareroutingfast-routemiddlewaresfast-router

### Embed Badge

![Health badge](/badges/karelwintersky-arrisrouter/health.svg)

```
[![Health](https://phpackages.com/badges/karelwintersky-arrisrouter/health.svg)](https://phpackages.com/packages/karelwintersky-arrisrouter)
```

###  Alternatives

[laravel/framework

The Laravel Framework.

34.9k556.2M21.3k](/packages/laravel-framework)[symfony/symfony

The Symfony PHP framework

31.4k87.4M2.2k](/packages/symfony-symfony)[matomo/matomo

Matomo is the leading Free/Libre open analytics platform

21.7k39.6k](/packages/matomo-matomo)[tempest/framework

The PHP framework that gets out of your way.

2.3k37.6k19](/packages/tempest-framework)[drupal/core

Drupal is an open source content management platform powering millions of websites and applications.

19467.3M1.9k](/packages/drupal-core)[drupal/core-recommended

Locked core dependencies; require this project INSTEAD OF drupal/core.

6943.5M448](/packages/drupal-core-recommended)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
