PHPackages                             adinan-cenci/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. adinan-cenci/router

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

adinan-cenci/router
===================

A small PHP router library.

v5.0.2(10mo ago)035MITPHPPHP &gt;=7.4

Since Jan 27Pushed 10mo ago1 watchersCompare

[ Source](https://github.com/adinan-cenci/router)[ Packagist](https://packagist.org/packages/adinan-cenci/router)[ RSS](/packages/adinan-cenci-router/feed)WikiDiscussions master Synced 2mo ago

READMEChangelog (10)Dependencies (3)Versions (20)Used By (0)

A small PHP router library
==========================

[](#a-small-php-router-library)

A simple PHP router to handle http requests.

This library is [PSR-15](https://www.php-fig.org/psr/psr-15/) compliant and therefore works with [PSR-7](https://www.php-fig.org/psr/psr-7/) messages and makes use of [PSR-17](https://www.php-fig.org/psr/psr-17/) factories.

Instantiating
-------------

[](#instantiating)

```
use AdinanCenci\Router\Router;
$r = new Router();
```

Adding routes
-------------

[](#adding-routes)

You may add routes by informing the http method, the regex pattern to be matched against the the path and the associated controller:

```
$r->add('get', '#home$#', 'controller');
```

### Http method

[](#http-method)

```
// You may inform a single http method:
$r->add('get', '#home#', 'controller')

// Or several inside an array ...
$r->add(['get', 'post'], '#home#', 'controller')

// Or in a pipe separated string
$r->add('get|post', '#home#', 'controller')

// Or use an sterisk to match all methods.
$r->add('*', '#home#', 'controller')
```

### Regex patterns

[](#regex-patterns)

A simple regex pattern. Capture groups will be passed to the controller as attributes.

**Obs**: The route accepts multiple patterns as an array.

```
$r->add('*', '#products/(?\d+)/(?\d+)#', function($request, $handler)
{
   $category  = $request->getAttribute('category', null);
   $productId = $request->getAttribute('id', null);
});
```

### Controllers

[](#controllers)

The controller will receive two paramaters: an instance of `Psr\Http\Message\ServerRequestInterface` and `Psr\Http\Server\RequestHandlerInterface` ( the router itself ) respectively.

By default, the routes accept various arguments as controllers:

```
$r->add('get', '#anonymous-function$#', function($request, $handler)
{
    echo 'Anonymous function';
})

//-------------

->add('get', '#named-function$#', 'namedFunction')

//-------------

->add('get', '#static-methods$#', ['MyClass', 'staticMethod'])
// A single string also works:
->add('get', '#static-methods$#', 'MyClass::staticMethod')

//-------------

->add('get', '#object-and-method$#', [$object, 'methodName'])

//-------------

->add('get', '#object$#', $object)
// The ::__invoke() magic method will be called.

//-------------

->add('get', '#class-and-method$#', ['MyClass', 'methodName'])
// It will attempt to instantiate the class first.
// A single string also works:
->add('get', '#class-and-method$#', 'MyClass::methodName')

//-------------

->add('get', '#class$#', ['MyClass'])
// It will attempt to instantiate the class and call the ::__invoke() magic method.

//-------------

// Of course, it also accepts instances of Psr\Http\Server\MiddlewareInterface
// ( see the PSR-15 specification for more information )
->add('get', '#psr-15$#', $middleware)
```

Those are the default controller types, see the contents of the "examples" directory for more detailed examples.

Check out the [advanced section](#custom-controller-types) below to learn how to add support for new types.

**Obs**: If the controller does not exist or cannot be called because of some reason or another, an exception will be thrown.

### ::add() shorthands

[](#add-shorthands)

```
// Examples
$r->get('#home#', $call);     /* is the same as */ $r->add('get', '#home#', $call);
$r->post('#home#', $call);    /* is the same as */ $r->add('post', '#home#', $call);
$r->put('#home#', $call);     /* is the same as */ $r->add('put', '#home#', $call);
$r->delete('#home#', $call);  /* is the same as */ $r->add('delete', '#home#', $call);
$r->options('#home#', $call); /* is the same as */ $r->add('options', '#home#', $call);
$r->patch('#home#', $call);   /* is the same as */ $r->add('patch', '#home#', $call);
```

Middlewares
-----------

[](#middlewares)

Middlewares will be processed before the routes.
Middlewares are similar to routes but unlike routes more than one middleware may be executed.

```
// Example
$r->before('*', '#restricted-area#', function($request, $handler)
{
    if (! userIsLogged()) {
        return $handler->responseFactory->movedTemporarily('/login-page');
    }
});
```

Executing
---------

[](#executing)

Calling `::run()` will execute the router and send a respose.

```
$r->run();
```

Error handling
--------------

[](#error-handling)

### Exceptions

[](#exceptions)

By default, catched exceptions will be rendered in a 500 response object, you may customize it by setting your own handler.

```
$r->setExceptionHandler(function($request, $handler, $path, $exception)
{
    return $handler->responseFactory
      ->internalServerError('Error 500 (' . $path . ')' . $exception->getMessage() . '');
});
```

### Not found

[](#not-found)

By default when no route is found, the router will render a 404 response object, you may customize it by setting your own handler.

```
$r->setNotFoundHandler(function($request, $handler, $path)
{
    return $handler->responseFactory
      ->internalServerError('Error 404Nothing found related to "' . $path . '"');
});
```

PSR compliance and niceties
---------------------------

[](#psr-compliance-and-niceties)

This library is [PSR-15](https://www.php-fig.org/psr/psr-15/) compliant, as such your controllers may tailor the response in details as specified in the [PSR-7](https://www.php-fig.org/psr/psr-7/).

**IMPORTANT**
If your controller does not return an instance of `ResponseInterface`, the router will create a generic response based out of whatever was outputed through `echo` and `print`.

Besides the defaults, the router offers some niceties.

### ::setDefaultNamespace($namespace)

[](#setdefaultnamespacenamespace)

Set the default namespace, so there will be no need to write the entire class name of the controller when defining routes.

```
// Example
$r->setDefaultNamespace('MyProject');

$r->add('get', '#home#', 'MyClass::method');
// If MyClass does not exist, the router will assume it refers to
// MyProject\MyClass::method()
```

### Factories

[](#factories)

The handler makes available a [PSR-17](https://www.php-fig.org/psr/psr-17/) response and stream factories to make creating responses more convenient.

```
$r->add('get', '#home$#', function($request, $handler)
{
   // Psr\Http\Message\ResponseFactoryInterface instance.
   $responseFactory = $handler->responseFactory;

   // Psr\Http\Message\StreamFactoryInterface instance.
   $streamFactory = $handler->streamFactory;
});
```

In this spirit of making things easier, the default response factory comes with a series of useful methods:

```
$responseFactory = $handler->responseFactory;

// Response with code 200
$responseFactory->ok('your html here');

// Response with code 201
$responseFactory->created('your html here');

// Response with code 301
$responseFactory->movedPermanently('https://redirect.here.com');

// Response with code 302
$responseFactory->movedTemporarily('https://redirect.here.com');

// Response with code 400
$responseFactory->badRequest('your html here');

// Response with code 401
$responseFactory->unauthorized('your html here');

// Response with code 403
$responseFactory->forbidden('your html here');

// Response with code 404
$responseFactory->notFound('your html here');

// Response with code 500
$responseFactory->internalServerError('your html here');

// Response with code 501
$responseFactory->notImplemented('your html here');

// Response with code 502
$responseFactory->badGateway('your html here');

// Response with code 503
$responseFactory->serviceUnavailable('your html here');
```

### Cookies

[](#cookies)

Similarly the response objects have the `::withAddedCookie()`:

```
$response = $responseFactory->ok('your html here');

$expires  = null;  // optional
$path     = '';    // optional
$domain   = '';    // optional
$secure   = false; // optional
$httpOnly = false; // optional

$response = $response->withAddedCookie('cookieName', 'cookieValue', $expires, $path, $domain, $secure, $httpOnly);
```

Advanced
--------

[](#advanced)

### Working inside sub-directories

[](#working-inside-sub-directories)

The router will automatically work inside sub-directories.

Consider the example: Your URL: `http://yourwebsite.com/foobar/about`

Your document root is
`/var/www/html/` and your router is inside of
`/var/www/html/foobar/`.

The router will match the routes against `about` and **NOT** `foobar/about`.

Still, if you really need to work with `foobar/about` , then you must pass `/var/www/html/` as your base directory to the `Router`'s constructor.

```
//               /var/www/html/foobar/index.php
$r = new Router('/var/www/html/');
```

### Factories

[](#factories-1)

The constructor's second and third parameters are a PSR-17 response and stream factories respectively.
If not provided, generic implementations will be used.

Those factories will made available to the controllers, as [explained earlier](#factories).

### Custom controller types

[](#custom-controller-types)

The constructor's fourth parameter is an instance of `AdinanCenci\Router\Caller\CallerInterface`, it is the object that will execute the controllers.

If not provided, the default caller will be used.
This default caller makes use of [several implementations](https://github.com/adinan-cenci/router/tree/master/src/Caller/Handler) of `AdinanCenci\Router\Caller\Handler\HandlerInterface` to support the different types of controllers [listed earlier](#controllers).

You can write your own handlers and callers to support your own version of a controller.

### Dependency injection

[](#dependency-injection)

So the router supports classes as controllers, how are they instantiated ?

The default `ClassHandler` and `MethodHandler` depend on an instance of `AdinanCenci\Router\Instantiator\InstantiatorInterface`.
The default implementation simply calls `new` to instantiate them.

If you wish use automatic dependency injection, you will need to provide your own caller/handler/instantiator.

How dependency injection is handled is beyond the escope of the library.

Server configuration
--------------------

[](#server-configuration)

In order for it to work, we need to rewrite the requests to the file containing our router. Below are some examples:

### Apache

[](#apache)

Here is the example of a .htaccess for Apache:

```
RewriteEngine on

# Condition: Requested resource does not exist
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteCond %{SCRIPT_FILENAME} !-d

# Rewrite to index.php
RewriteRule ^.{1,}$   index.php   [QSA]

```

### Nginx

[](#nginx)

Here is the example for nginx:

```
location / {
    if ($script_filename !~ "-f") {
        rewrite "^/.{1,}$" /index.php;
    }
}

```

### IIS

[](#iis)

Here is the example of a web.config for Microsoft IIS:

```

```

Installing
----------

[](#installing)

Use composer

```
composer require adinan-cenci/router

```

License
-------

[](#license)

MIT

###  Health Score

38

—

LowBetter than 85% of packages

Maintenance53

Moderate activity, may be stable

Popularity7

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity72

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

Recently: every ~224 days

Total

16

Last Release

324d ago

Major Versions

0.2.0 → 1.0.02019-10-13

1.0.1 → 2.0.02020-02-01

2.1.1 → 3.0.02021-02-01

3.0.2 → v4.0.02023-01-08

v4.0.1 → v5.0.02024-12-26

PHP version history (2 changes)0.1.0PHP &gt;=5.3

v4.0.0PHP &gt;=7.4

### Community

Maintainers

![](https://www.gravatar.com/avatar/3c1eb1b039e965bb307f010fb1dd41fbc79c8c9e9a65324b8f18d2bb9168097d?d=identicon)[AdinanCenci](/maintainers/AdinanCenci)

---

Top Contributors

[![adinan-cenci](https://avatars.githubusercontent.com/u/1629643?v=4)](https://github.com/adinan-cenci "adinan-cenci (76 commits)")

---

Tags

httppsrpsr-7psr-17routerpsr-15

### Embed Badge

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

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

###  Alternatives

[psr/http-server-middleware

Common interface for HTTP server-side middleware

18091.2M1.5k](/packages/psr-http-server-middleware)[mezzio/mezzio

PSR-15 Middleware Microframework

3883.6M97](/packages/mezzio-mezzio)[laminas/laminas-stratigility

PSR-7 middleware foundation for building and dispatching middleware pipelines

586.6M81](/packages/laminas-laminas-stratigility)[sunrise/http-router

A powerful solution as the foundation of your project.

16249.8k10](/packages/sunrise-http-router)[middlewares/utils

Common utils for PSR-15 middleware packages

503.4M92](/packages/middlewares-utils)[middlewares/fast-route

Middleware to use FastRoute

96191.1k15](/packages/middlewares-fast-route)

PHPackages © 2026

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