PHPackages                             phossa2/route - 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. phossa2/route

AbandonedLibrary[Framework](/categories/framework)

phossa2/route
=============

A fast and full-fleged routing library for PHP

2.0.0(9y ago)316MITPHP ~5.4|~7.0

Since Aug 26Compare

[ Source](https://github.com/phossa2/route)[ Packagist](https://packagist.org/packages/phossa2/route)[ Docs](https://github.com/phossa2/route)[ RSS](/packages/phossa2-route/feed)WikiDiscussions Synced yesterday

READMEChangelog (1)Dependencies (4)Versions (2)Used By (0)

phossa2/route \[ABANDONED\]
===========================

[](#phossa2route-abandoned)

**PLEASE USE [phoole/route](https://github.com/phoole/route) library instead**

[![Build Status](https://camo.githubusercontent.com/92479383bad7f1ae2b4d1e83da2f162b58da7f1a0869e34e8506b0828525a58e/68747470733a2f2f7472617669732d63692e6f72672f70686f737361322f726f7574652e7376673f6272616e63683d6d6173746572)](https://travis-ci.org/phossa2/route)[![Code Quality](https://camo.githubusercontent.com/00a6d7884024704b9e1423c0344114c97799a7c5a64e38340119882985acfba9/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f70686f737361322f726f7574652f6261646765732f7175616c6974792d73636f72652e706e673f623d6d6173746572)](https://scrutinizer-ci.com/g/phossa2/route/)[![Code Climate](https://camo.githubusercontent.com/1fdd692a9a8aa12b89cef65a6159a2cb68ce5da5cda7637f87666fe8db36d69a/68747470733a2f2f636f6465636c696d6174652e636f6d2f6769746875622f70686f737361322f726f7574652f6261646765732f6770612e737667)](https://codeclimate.com/github/phossa2/route)[![PHP 7 ready](https://camo.githubusercontent.com/367066442a002f66ea0334b8009c6dcc1a9544068b38f48710647a904925a88f/687474703a2f2f7068703772656164792e74696d6573706c696e7465722e63682f70686f737361322f726f7574652f6d61737465722f62616467652e737667)](https://travis-ci.org/phossa2/route)[![HHVM](https://camo.githubusercontent.com/01bcaab5fef6f28fe385ed58a70fbd414b57076459e2bcbf2b9b680fd600c0e0/68747470733a2f2f696d672e736869656c64732e696f2f6868766d2f70686f737361322f726f7574652e7376673f7374796c653d666c6174)](http://hhvm.h4cc.de/package/phossa2/route)[![Latest Stable Version](https://camo.githubusercontent.com/cee939fa835e04347636bcc13cc34da90804b3e7f51e0996267126ec73373b1b/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f767072652f70686f737361322f726f7574652e7376673f7374796c653d666c6174)](https://packagist.org/packages/phossa2/route)[![License](https://camo.githubusercontent.com/4fc6538ded72843e26a272d300ce4c95da083ce92576e10e4fdd505d579a8125/68747470733a2f2f696d672e736869656c64732e696f2f3a6c6963656e73652d6d69742d626c75652e737667)](http://mit-license.org/)

**phossa2/route** is a *fast*, *full-fledged* and *feature-rich* application level routing library for PHP.

It requires PHP 5.4, supports PHP 7.0+ and HHVM. It is compliant with [PSR-1](http://www.php-fig.org/psr/psr-1/ "PSR-1: Basic Coding Standard"), [PSR-2](http://www.php-fig.org/psr/psr-2/ "PSR-2: Coding Style Guide"), [PSR-3](http://www.php-fig.org/psr/psr-3/ "PSR-3: Logger Interface"), [PSR-4](http://www.php-fig.org/psr/psr-4/ "PSR-4: Autoloader"), and the proposed [PSR-5](https://github.com/phpDocumentor/fig-standards/blob/master/proposed/phpdoc.md "PSR-5: PHPDoc").

Why another routing library ?
-----------------------------

[](#why-another-routing-library-)

- [Super fast](#performance) ! If it matters to you.
- Support different [routing strategies](#strategy) and combinations of these strategies.
- Support different [regular expression routing algorithms](#algorithm)including the [fastRoute algorithm](#fastroute)
- [Concise route syntax](#syntax). Route parameters and optional route segments.
- Fast routing using [path prefix checking](#prefix) in the collectors.
- [Multiple routing collections](#collector) allowed.
- Different level of [default handlers](#default).
- Fine control of routing process by [multiple level of extensions](#extension).
- Route and regex [debugging](#debug).

Installation
------------

[](#installation)

Install via the `composer` utility.

```
composer require "phossa2/route"
```

or add the following lines to your `composer.json`

```
{
    "require": {
       "phossa2/route": "2.*"
    }
}
```

Usage
--------------------------------------

[](#usage)

Inject route definitions (pattern, handler, default values etc.) into the dispatcher and then call either `match()` or `dispatch()`.

```
use Phossa2\Route\Route;
use Phossa2\Route\Dispatcher;

// dispatcher with default collector & resolver
$dispatcher = (new Dispatcher())
    ->addGet(
        '/blog/{action:xd}[/{year:d}[/{month:d}[/{date:d}]]]',
        function($result) {
            $params = $result->getParameters();
            echo "action is " . $params['action'];
        }
    )->addPost(
        '/blog/post',
        'handler2'
    )->addRoute(new Route(
        'GET,HEAD',
        '/blog/read[/{id:d}]',
        'handler3',
        ['id' => '1'] // default values
    ));

// diaptcher (match & execute controller action)
$dispatcher->dispatch('GET', '/blog/list/2016/05/01');
```

Or load routes from an array,

```
$routes = [
    '/user/{action:xd}/{id:d}' => [
        'GET,POST',               // methods,
        function ($result) {
            $params = $result->getParameters();
            echo "user id is " . $params['id'];
        },                        // handler,
        ['id' => 1]               // default values
    ],
    // ...
];
$dispatcher = (new Dispatcher())->loadRoutes($routes);
$dispatcher->dispatch('GET', '/user/view/123456');
```

Route syntax
----------------------------------------------

[](#route-syntax)

- **{Named} parameters**

    A route pattern syntax is used where `{foo}` specifies a named parameter or a placeholder with name `foo` and default regex pattern `[^/]++`. In order to match more specific types, you may specify a custom regex pattern like `{foo:[0-9]+}`.

    ```
    // with 'action' & 'id' two named params
    $dispatcher->addGet('/user/{action:[^0-9/][^/]*}/{id:[0-9]+}', 'handler1');
    ```

    Predefined shortcuts can be used for placeholders as follows,

    ```
    ':d}'   => ':[0-9]++}',             // digit only
    ':l}'   => ':[a-z]++}',             // lower case
    ':u}'   => ':[A-Z]++}',             // upper case
    ':a}'   => ':[0-9a-zA-Z]++}',       // alphanumeric
    ':c}'   => ':[0-9a-zA-Z+_\-\.]++}', // common chars
    ':nd}'  => ':[^0-9/]++}',           // not digits
    ':xd}'  => ':[^0-9/][^/]*+}',       // no leading digits
    ```

    The previous pattern can be rewritten into,

    ```
    // with 'action' & 'id' two named params
    $dispatcher->addGet('/user/{action:xd}/{id:d}', 'handler1');
    ```
- **\[Optional\] segments**

    Optional segments in the route pattern can be specified with `[]` as follows,

    ```
    // $action, $year/$month/$date are all optional
    $pattern = '/blog[/{action:xd}][/{year:d}[/{month:d}[/{date:d}]]]';
    ```

    where optional segments can be **NESTED**. Unlike other libraries, optional segments are not limited to the end of the pattern, as long as it is a valid pattern like the `[/{action:xd}]` in the example.
- **Syntax limitations**

    - Parameter name *MUST* start with a character

        Since `{2}` has special meanings in regex. Parameter name *MUST* start with a character. And the use of `{}` inside/outside placeholders may cause confusion, thus is not recommended.
    - `[]` outside placeholder means *OPTIONAL* segment only

        `[]` can not be used outside placeholders as part of a regex pattern, *IF YOU DO NEED* to use them as part of the regex pattern, please include them *INSIDE* a placeholder.
    - Use of capturing groups `()` inside placeholders is not allowed

        Capturing groups `()` can not be used inside placeholders. For example `{user:(root|phossa)}` is not valid. Instead, you can use either use `{user:root|phossa}` or `{user:(?:root|phossa)}`.
- **Default Values**

    Default values can be added to named parameters at the end in the form of `{action:xd=list}`. Default values have to be alphanumeric chars. For example,

    ```
    // $action, $year/$month/$date are all optional
    $pattern = '/blog[/{action:xd=list}][/{year:d=2016}[/{month:d=01}[/{date:d=01}]]]';
    $dispatcher->addGet($pattern, function($result) {
        $params = $result->getParameters();
        echo $params['year'];
    })->dispatch('GET', '/blog');
    ```

Routes
----------------------------------------

[](#routes)

- **Defining routes with dispatcher**

    You may define routes with dispatcher. But, it is actually defining routes with the first route collector in the dispatcher.

    ```
    // a new route collector will be added automatically if not yet
    $dispatcher = (new Dispatcher())->addPost('/blog/post', 'handler2');
    ```

    `addGet()` and `addPost()` are wrappers of `addRoute(RouteInterface)`.
- **Multiple routing collectors**

    Routes can be grouped into different collections by using multiple collectors.

    ```
    use Phossa2\Route\Collector\Collector;

    // '/user' related
    $collector_user = (new Collector())
        ->addGet('/user/list/{id:d}', 'handler1')
        ->addGet('/user/view/{id:d}', 'handler2')
        ->addPost('/user/new', 'handler3');

    // '/blog' related
    $collector_blog = (new Collector())
        ->addGet('/blog/list/{user_id:d}', 'handler4')
        ->addGet('/blog/read/{blog_id:d}', 'handler5');

    $dispatcher->addCollector($collector_user)
               ->addCollector($collector_blog);
    ```
- **Path prefix matching**

    Collectors may set a path prefix using `setPathPrefix()` to indicate the exact URI path prefix is handling. Any non-matching prefix found will skip the collector entirely.

    ```
    // '/user/' prefix
    $collector_user = (new Collector())
        ->setPathPrefix('/user/')
        ->addGet('/user/list/{id:d}', 'handler1')
        ->addGet('/user/view/{id:d}', 'handler2')
        ->addPost('/user/new', 'handler3');
    ```
- **Same route pattern**

    User can define same route pattern with different http methods.

    ```
    $dispatcher
        ->addGet('/user/{$id}', 'handler1')
        ->addPost('/user/{$id}', 'handler2');
    ```

Dispatching
-----------------------------------------------

[](#dispatching)

- **Dispatch with dispatcher's `dispatch()`**

    ```
    $dispatcher->dispatch('GET', '/user/view/123');
    ```
- **Match instead of dispatching**

    Instead of executing handler by default in `dispatch()`, more control by user if using the `match()` method

    ```
    if ($dispatcher->match('GET', '/user/view/1234')) {
        $result = $dispatcher->getResult();
        switch($result->getStatus()) {
            case 200:
              // ...
              break;
            case 404:
              // ...
              break;
            default:
              // ...
              break;
        }
    } else {
        // no match found
        // ...
    }
    ```

Handlers
-------------------------------------------

[](#handlers)

- **Route handler**

    Route is defined with a handler for status `200 OK` only.

    ```
    use Phossa2\Route\Route;
    use Phossa2\Route\Status;

    $route = new Route(
        'GET',
        '/user/{action:xd}/{id:d}',
        function($result) { // handler for Status::OK
            // ...
        }
    );
    ```
- **Default handlers**

    Dispatcher and collectors can have multiple handlers corresponding to different result status.

    If the result has no handler set (for example, no match found), then the collector's handler(same status code) will be retrieved. If still no luck, the dispatcher's handler (same status code) will be used if defined.

    Dispatcher-level handlers,

    ```
    use Phossa2\Route\Status;

    $dispatcher->addHandler(
        function($result) {
            echo "method " . $result->getMethod() . " not allowed";
        },
        Status::METHOD_NOT_ALLOWED
    );
    ```

    Collector-level handlers,

    ```
    $collector->addHandler(
        function($result) {
            // ...
        },
        Status::MOVED_PERMANENTLY
    );
    ```

    When `addHandler()` with status set to `0` will cause this handler be the default handler for other status.

    ```
    use Phossa2\Route\Status;

    $dispatcher->addHandler(
        function($result) {
            echo "no other handler found";
        },
        0 // addExtension(new RedirectToHttps())
        ->addHandler(function() {
              echo "redirect to https";
          }, Status::MOVED_PERMANENTLY)
        ->dispatch('GET', '/user/view/123');
    ```

    Force authentication for any '/user/' prefixed URL,

    ```
    use Phossa2\Route\Status;
    use Phossa2\Route\Dispatcher;
    use Phossa2\Route\Extensions\UserAuth;

    $dispatcher = new Dispatcher();

    $dispatcher
      // add handler for unauthorized routing
      ->addHandler(
          function() {
              echo "need auth";
          }, Status::UNAUTHORIZED)

      // add a route
      ->addGet('/user/view/{id:d}', function() {
              echo "AUTHED!";
          })

      // add extension to force auth routes under '/user/'
      ->addExt(function($event) {
              $result = $event->getParam('result');
              $path = $result->getPath();
              if (!isset($_SESSION['authed']) && '/user/' === substr($path, 0, 6)) {
                  $result->setStatus(Status::UNAUTHORIZED);
                  return false;
              }
              return true;
          }, Dispatcher::EVENT_BEFORE_MATCH);

    // try a not authed route
    $dispatcher->dispatch('GET', '/user/view/123');

    // try a authed route
    $_SESSION['authed'] = 1;
    $dispatcher->dispatch('GET', '/user/view/123');
    ```
- **Examples of extension**

    Validation of a parameter value on a route,

    ```
    use Phossa2\Route\Status;
    use Phossa2\Route\Dispatcher;
    use Phossa2\Route\Extensions\IdValidation;

    $dispatcher = new Dispatcher();

    // add extension to a route
    $route = (new Route('GET', '/user/{id:d}', null))
      ->addExtension(new IdValidation());

    // will fail
    $dispatcher->addRoute($route)->dispatch('GET', '/user/1000');
    ```
- **Extension events**

    Three types of events, dispatcher level, collector level and route level. List of all events in the order of execution.

    - `Dispatcher::EVENT_BEFORE_MATCH` before matching starts

        - `Collector::EVENT_BEFORE_MATCH` before matching in a collector
        - `Collector::EVENT_AFTER_MATCH` after a successful match in the collector
    - `Dispatcher::EVENT_AFTER_MATCH` after a successful match at dispatcher level
    - `Dispatcher::EVENT_BEFORE_DISPATCH` after a sucessful match, before dispatching to any handler

        - `Route::EVENT_BEFORE_HANDLER` before executing handler(route's or collector's) for this route
        - `Route::EVENT_AFTER_HANDLER` after handler successfully executed
    - `Dispatcher::EVENT_AFTER_DISPATCH` back to dispatcher level, after handler executed successfully
    - `Dispatcher::EVENT_BEFORE_HANDLER` match failed or no handler found for the matching route, before execute dispatcher's default handler
    - `Dispatcher::EVENT_AFTER_HANDLER` after dispatcher's default handler executed

Debugging
------------------------------------------

[](#debugging)

Sometimes, you need to know what went wrong.

```
$dispatcher->enableDebug()->setDebugger($logger);
```

Where `$logger` is a PSR-3 compatible logger implmenting the interface `Psr\Log\LoggerInterface`. The dispatcher will send logs of dispatching process to the logger.

Routing strategies
------------------------------------------------------

[](#routing-strategies)

There are a couple of URL based routing strategies supported in this library. Different strategy collectors can be combined together into one dispatcher.

- **Parameter Pairs Routing (PPR)**

    Using parameter and value pairs for routing,

    ```
    http://servername/path/index.php/controller/action/id/1/name/nick

    ```

    Parameters order can be arbitary, but have to appear in pairs. Advantage of this scheme is fast and web crawler friendly. If URL rewriting is used, the above can be written into the following,

    ```
    http://servername/path/controller/action/id/1/name/nick

    ```

    Instead of using '/' as the parameter seperator, any URL valid characters except for the '?' and '&amp;' can be used as a seperator.

    ```
    http://servername/path/controller-action-id-1-name-nick

    ```

    This strategy is implemented in `Phossa2\Route\Collector\CollectorPPR` class.
- **Query Parameter Routing (QPR)**

    The routing info is directly embedded in the URL query. The advantage of this scheme is fast and clear.

    ```
    http://servername/path/?r=controller-action-id-1-name-nick

    ```

    This strategy is implemented in `Phossa2\Route\Collector\CollectorQPR` class.
- **Regular Expression Routing (RER)**

    Regular expression based routing is the default routing strategy for this library and implemented in `Phossa2\Route\Collector\Collector` class.

    ```
    // created with default RER collector
    $dispatcher = (new Dispatcher())
        ->addCollector(new Collector())     // regex based routing first
        ->addCollector(new CollectorQPR()); // support for legacy QPR
    ```

Regex matching algorithms
--------------------------------------------------------------

[](#regex-matching-algorithms)

Different regex matching algorithms can be used with the RER collector.

- **FastRoute algorithm**

    This *Group Count Based algorithm* is implemented in `Phossa2\Route\Parser\ParserGcb` class and explained in detail in this article ["Fast request routing using regular expressions"](http://nikic.github.io/2014/02/18/Fast-request-routing-using-regular-expressions.html).

    phossa-route uses this algorithm by default.
- **Standard algorithm**

    This algorithm is developed by phossa2/route and a little bit slower than the fastRoute GCB algorithm. It is implemented in `Phossa2\Route\Parser\ParserStd`class.

    Use this standard algorithm,

    ```
    use Phossa2\Route\Dispatcher;
    use Phossa2\Route\Parser\ParserStd;
    use Phossa2\Route\Collector\Collector;

    // use standard algorithm
    $dispatcher = new Dispatcher(new Collector(new ParserStd));
    ```
- **Comments on routing algorithms**

    - It does **NOT** matter that much as you may think.

        If you are using routing library in your application, different algorithms may differ only 0.1 - 0.2ms for a single request, which seems meaningless for an application unless you are using it as a standalone router.
    - If you **DO** care about routing speed

        Use different routing strategy like [*Parameter Pairs Routing (PPR)*](#ppr)which is [much faster](#performance) than the regex based routing. Also by carefully design your routes, you may achieve better results even if you are using a *slower* algorithm.
    - Try [network routing or server routing](#issue) if you just **CRAZY ABOUT THE SPEED**.

Change log
----------

[](#change-log)

Please see [CHANGELOG](CHANGELOG.md) from more information.

Testing
-------

[](#testing)

```
$ composer test
```

Contributing
------------

[](#contributing)

Please see [CONTRIBUTE](CONTRIBUTE.md) for more information.

Dependencies
------------

[](#dependencies)

- PHP &gt;= 5.4.0
- phossa2/event &gt;= 2.1.5
- phossa2/shared &gt;= 2.0.27

License
-------

[](#license)

[MIT License](http://mit-license.org/)

Appendix
--------

[](#appendix)

- **Performance**

    - Worst-case matching

        This benchmark matches the last route and unknown route. It generates a randomly prefixed and suffixed route in an attempt to thwart any optimization. 1,000 routes each with 8 arguments.

        This benchmark consists of 14 tests. Each test is executed 1,000 times, the results pruned, and then averaged. Values that fall outside of 3 standard deviations of the mean are discarded.

        ["Parameter Pairs Routing (PPR)"](#ppr) is fastest and used as baseline.

        Test NameResultsTime+ IntervalChangePhossa PPR - unknown route (1000 routes)9980.0000724551+0.0000000000baselinePhossa PPR - last route (1000 routes)9930.0000925307+0.000020075528% slowerSymfony2 Dumped - unknown route (1000 routes)9980.0004353616+0.0003629065501% slowerPhroute - last route (1000 routes)9990.0006205601+0.0005481050756% slowerPhossa - unknown route (1000 routes)9980.0006903790+0.0006179239853% slowerFastRoute - unknown route (1000 routes)1,0000.0006911943+0.0006187392854% slowerFastRoute - last route (1000 routes)9990.0006962751+0.0006238200861% slowerPhroute - unknown route (1000 routes)9980.0007134676+0.0006410125885% slowerSymfony2 Dumped - last route (1000 routes)9930.0008066097+0.00073415451013% slowerPhossa - last route (1000 routes)9980.0009104498+0.00083799471157% slowerSymfony2 - unknown route (1000 routes)9890.0023998006+0.00232734553212% slowerSymfony2 - last route (1000 routes)9990.0025880890+0.00251563393472% slowerAura v2 - last route (1000 routes)9810.0966411463+0.0965686912133281% slowerAura v2 - unknown route (1000 routes)9920.1070026719+0.1069302168147581% slower
    - First route matching

        This benchmark tests how quickly each router can match the first route. 1,000 routes each with 8 arguments.

        This benchmark consists of 7 tests. Each test is executed 1,000 times, the results pruned, and then averaged. Values that fall outside of 3 standard deviations of the mean are discarded.

        **Note** Both *FastRoute* and *Phroute* implement a static route table, so they are fast at the first route matching (which is a static route)

        Test NameResultsTime+ IntervalChangeFastRoute - first route9990.0000403543+0.0000000000baselinePhroute - first route9980.0000405911+0.00000023681% slowerSymfony2 Dumped - first route9990.0000590617+0.000018707446% slowerPhossa PPR - first route9770.0000678727+0.000027518468% slowerPhossa - first route9990.0000898475+0.0000494932123% slowerSymfony2 - first route9980.0003983802+0.0003580259887% slowerAura v2 - first route9860.0004391784+0.0003988241988% slower
- **URL rewrite**

    Setup URL rewriting to do routing with `index.php`

    - Apache `.htaccess` with `mod_rewrite` engine is on

        ```
        DirectorySlash Off
        Options -MultiViews
        DirectoryIndex index.php
        RewriteEngine On
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteCond %{REQUEST_FILENAME} !-l
        RewriteRule ^ index.php [QSA,L]

        ```

        and in your `httpd.conf` file to enable using of `.htaccess`

        ```

          ServerAdmin me@mysite.com
          DocumentRoot "/path/www.mysite.com/public"
          ServerName mysite.com
          ServerAlias www.mysite.com

            Options -Indexes +FollowSymLinks +Includes
            AllowOverride All
            Order allow,deny
            Allow from all

        ```
    - Nginx configration in `nginx.conf`

        ```
        server {
            listen       80;
            server_name  www.mysite.com mysite.com;
            root         /path/www.mysite.com/public;

            try_files $uri $uri/ /index.php$is_args$args;

            location /index.php {
                fastcgi_connect_timeout 3s;
                fastcgi_read_timeout 10s;
                include fastcgi.conf;
                fastcgi_pass 127.0.0.1:9000;
            }
        }

        ```
- **Routing issues**

    Base on the request informations, such as request device, source ip, request method etc., service provider may direct request to different hosts, servers, app modules or handlers.

    - *Network level routing*

        Common case, such as routing based on request's source ip, routes the request to a *NEAREST* server, this is common in content distribution network (CDN), and is done at network level.
    - *Web server routing*

        For performance reason, some of the simple routing can be done at web server level, such as using apache or ngix configs to do simple routing.

        For example, if your server goes down for maintenance, you may replace the `.htaccess` file as follows,

        ```
        DirectorySlash Off
        Options -MultiViews
        DirectoryIndex maintenance.php
        RewriteEngine On
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteCond %{REQUEST_FILENAME} !-l
        RewriteRule ^ maintenance.php [QSA,L]

        ```
    - *App level routing*

        It solves much more complicated issues, and much more flexible.

        Usually, routing is done at a single point `index.php`. All the requests are configured to be handled by this script first and routed to different routines.

###  Health Score

26

—

LowBetter than 41% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity9

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity58

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 92.6% 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

Unknown

Total

1

Last Release

3596d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/19922046?v=4)[Hong Zhang](/maintainers/phossa2)[@phossa2](https://github.com/phossa2)

---

Top Contributors

[![phossa](https://avatars.githubusercontent.com/u/8499165?v=4)](https://github.com/phossa "phossa (25 commits)")[![phossa2](https://avatars.githubusercontent.com/u/19922046?v=4)](https://github.com/phossa2 "phossa2 (2 commits)")

---

Tags

routephossa

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/phossa2-route/health.svg)

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

###  Alternatives

[pecee/simple-router

Simple, fast PHP router that is easy to get integrated and in almost any project. Heavily inspired by the Laravel router.

697231.0k18](/packages/pecee-simple-router)[izniburak/router

simple router class for php

23323.2k7](/packages/izniburak-router)[lesichkovm/laravel-advanced-route

Advanced route class for Laravel - restoring implicit controllers to the framework.

70144.6k1](/packages/lesichkovm-laravel-advanced-route)[ecoal95/php-router

Minimal routing library

271.0k1](/packages/ecoal95-php-router)[rosengate/exedra

Nestful route oriented PHP micro framework

142.0k1](/packages/rosengate-exedra)[developermarius/simple-router

Simple, fast PHP router that is easy to get integrated and in almost any project. Heavily inspired by the Laravel router.

112.5k](/packages/developermarius-simple-router)

PHPackages © 2026

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