PHPackages                             fizk/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. [HTTP &amp; Networking](/categories/http)
4. /
5. fizk/router

ActiveLibrary[HTTP &amp; Networking](/categories/http)

fizk/router
===========

A very simple PSR-7 Router

2.1.0(3y ago)084MITPHPPHP &gt;=8.1

Since Feb 9Pushed 3y ago1 watchersCompare

[ Source](https://github.com/fizk/Router)[ Packagist](https://packagist.org/packages/fizk/router)[ RSS](/packages/fizk-router/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (4)Dependencies (3)Versions (5)Used By (0)

Router.
=======

[](#router)

A very simple PRS-7 compatible router.

How it works.
-------------

[](#how-it-works)

This Router doesn't try to be smart or clever. It doesn't have an opinion on what's it's routing. It doesn't re-write a route expression into RegExp, instead, it wants the expression to be expressed in a Regular Expression upfront. This allows greater control on what will be match against a URI.

This Router is constructed as a tree. This makes the Router that just a little bit faster as it doesn't need to go through a whole list (and every route definition) to find a match.

 2 3 4 1 How to use it.
--------------

[](#how-to-use-it)

Define a Route, give it a name, an Expression and the Parameters you want returned when the Route is a match, then match it against a [PSR-7 Request](https://www.php-fig.org/psr/psr-7/)

```
use Fizk\Router\Route;
use Laminas\Diactoros\Request;

$routes = new Route(
    'root',
    '/path/(?\d+)',
    ['handler' => SomeHandler::class]
);

$request = new Request('http://this.is/path/1');

$match = $routes->match($request);

print_r($match->getAttributes())
// Will print
//[
//  'id' => '1'
//]

print_r($match->getParams())
// Will print
//[
//  'handler' => 'Namespace\\SomeHandler'
//]
```

As you can see, there is none of that `/path/:id` syntax, instead you need to write the full expression. If you want to capture the Attributes in the URI, you have to give them a name by using [Named Captures](https://php.watch/articles/php-regex-readability#named-captures)

### Nested routes.

[](#nested-routes)

Let's say we have a root path: `/path` and then we can have either numbers or letters as Attributes and we want different handlers/controller to run depending on which type Attribute is provided. We can express it like this:

```
use Fizk\Router\Route;
use Laminas\Diactoros\Request;

$routes = (new Route('path', '/path', []))
    ->addRoute(new Route('letters', '/(?[a-z]+)', ['controller' => SomeLetterController::class]))
    ->addRoute(new Route('number', '/(?\d+)', ['controller' => SomeNumberController::class]))
    ;

echo $routes->match(new Request('http://this.is/path/1'))->getParam('handler');
// Will print
// Namespace\\SomeNumberController

echo $routes->match(new Request('http://this.is/path/arg'))->getParam('handler');
// Will print
// Namespace\\SomeLetterController
```

Routes can be nested "infinitely" deep.

### The Router Class.

[](#the-router-class)

Defining routes with the `->addRoute(...)` syntax can be a bit verbose. This library provides a class than can take in configuration as an array and build the Router Tree, that way the router configuration is a little bit simpler to manage.

```
// router.config.php
return [
    'base' => [
        'pattern' => '/',
        'options' => ['handler' => 'IndexHandler'],
    ],
    'albums' => [
        'pattern' => '/albums',
        'options' => ['handler' => 'AlbumsHandler'],
        'children' => [
            'album' => [
                'pattern' => '/(?\d+)',
                'options' => ['handler' => 'AlbumHandler'],
            ],
        ]
    ],
];
```

```
// index.php

$router = new Router(require './router.config.php');

$request = new Request('http://example.com/albums/1');
echo $router->match($request)->getParams('handler');

// Will print
// AlbumHandler
```

The array key will become the name of the Route. The required `pattern` and `options` keys will be passed to the Route instance. An optional `children` key can be defined, those routes will become children of the parent route.

Because this class has all the configuration inside of it, it can provide a method called `public function construct(string $path, ?array $arguments = []): ?string;` It can construct a URI based off the names you have given to the Routes. An example of this would be:

```
$config = [
    'index' => [
        'pattern' => '/',
        'options' => ['handler' => 'IndexHandler'],
    ],
    'albums' => [
        'pattern' => '/albums',
        'options' => ['handler' => 'AlbumsHandler'],
        'children' => [
            'album' => [
                'pattern' => '/(?\d+)',
                'options' => ['handler' => 'AlbumHandler'],
            ],
        ]
    ],
];

$router = new Router($config);
echo $router->construct('albums/album', ['id' => 1]);

// This will print
//  /albums/1
```

Example
-------

[](#example)

This examples uses `Fizk\Router` in conjunction with `Psr\Http\Message\ResponseInterface` and `Psr\Http\Message\ServerRequestInterface`. What is important to understand is that the Router is not going in inject any values from the URI into the `$responce` object or invoke the Controller/Handler. These are things you have to manage on your own.

The benefit of this is that the Router is not dependent on how Controllers/Handlers are implemented or which PSR standard it is using.

```
use Fizk\Router\Route;
use Laminas\Diactoros\Request;
use Laminas\Diactoros\Response\JsonResponse;
use Laminas\HttpHandlerRunner\Emitter\SapiEmitter;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

//Define Handlers/Controllers
class SomeNumberController implements RequestHandlerInterface
{
    public function handle(ServerRequestInterface $request): ResponseInterface
    {
        $id = $request->getAttribute('id');
        $data = $service->getById($id);
        return new JsonResponse($data);
    }
}

class SomeLetterController implements RequestHandlerInterface
{
    public function handle(ServerRequestInterface $request): ResponseInterface
    {
        $slug = $request->getAttribute('slug');
        $data = $service->getBySlug($slug);
        return new JsonResponse($slug);
    }
}

class ResourceNotFoundController implements RequestHandlerInterface
{
    public function handle(ServerRequestInterface $request): ResponseInterface
    {
        return new JsonResponse(['message' => 'Resource Not Found'], 404);
    }
}

// Create a Request Object, pulling CGI values from global scope
$request = ServerRequestFactory::fromGlobals(
    $_SERVER,
    $_GET,
    $_POST
    $_COOKIE,
    $_FILES
);
// Define an Emitter, which will set HTTP headers and body before delivering to client
$emitter = new SapiEmitter();

// Define Routes
$routes = (new Route('path', '/path', []))
    ->addRoute(new Route('letters', '/(?[a-z]+)', ['controller' => new SomeLetterController()]))
    ->addRoute(new Route('number', '/(?\d+)', ['controller' => new SomeNumberController]))
    ;

// ...OR USE THE MORE COMPACT WAY OF DEFINING ROUTES
$routes = new Router([
    'path' => [
        'pattern' => '/path',
        'options' => []
        'children' => [
            'letters' => [
                'pattern' => '/(?[a-z]+)',
                'options' => ['controller' => new SomeLetterController()]
            ],
            'numbers' => [
                'pattern' => '/(?\d+)',
                'options' => ['controller' => new SomeNumberController()]
            ],
        ]
    ]
]);

// Match Routes against Request Object
$match = $routes->match($request);

if ($match) {
    //Add attributes from URI to the Request Object
    foreach ($match->getAttributes() as $name => $value) {
        $request = $request->withAttribute($name, $value);
    }

    // Run the Handler/Controller
    $response = $match->getParam('controller')->handle($request);

    // Emit a Response back to client
    $emitter->emit($response);
} else {
    // Run the Error Handler/Controller
    $response = (new ResourceNotFoundController())->handle($request);

    // Emit a Response back to client
    $emitter->emit($response);
}
```

###  Health Score

27

—

LowBetter than 49% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity9

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity61

Established project with proven stability

 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 ~124 days

Total

4

Last Release

1186d ago

Major Versions

1.1.0 → 2.0.02023-02-02

### Community

Maintainers

![](https://www.gravatar.com/avatar/85ed025c129290e8844017c0c02caf52b0f2850f7f44b37dad902b05fe9a3ee3?d=identicon)[fizk](/maintainers/fizk)

---

Top Contributors

[![fizk](https://avatars.githubusercontent.com/u/386336?v=4)](https://github.com/fizk "fizk (5 commits)")

---

Tags

psr-7router

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/fizk-router/health.svg)

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

###  Alternatives

[league/route

Fast routing and dispatch component including PSR-15 middleware, built on top of FastRoute.

6633.1M115](/packages/league-route)[aura/router

Powerful, flexible web routing for PSR-7 requests.

5231.5M67](/packages/aura-router)[sunrise/http-router

A powerful solution as the foundation of your project.

16249.8k10](/packages/sunrise-http-router)[phpro/http-tools

HTTP tools for developing more consistent HTTP implementations.

28137.8k](/packages/phpro-http-tools)

PHPackages © 2026

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