PHPackages                             gac/routing - 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. [API Development](/categories/api)
4. /
5. gac/routing

ActiveLibrary[API Development](/categories/api)

gac/routing
===========

Custom routing library especially useful for fast API development

v3.1.7(1y ago)81.4k2[4 issues](https://github.com/gigili/PHP-routing/issues)[1 PRs](https://github.com/gigili/PHP-routing/pulls)GPL-3.0-onlyPHPPHP &gt;=8.0CI failing

Since Mar 31Pushed 1y ago1 watchersCompare

[ Source](https://github.com/gigili/PHP-routing)[ Packagist](https://packagist.org/packages/gac/routing)[ Docs](https://github.com/gigili/PHP-routing)[ Fund](https://ko-fi.com/igorilic)[ Fund](https://paypal.me/igorili)[ RSS](/packages/gac-routing/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (10)Dependencies (1)Versions (36)Used By (0)

Routing library for PHP
=======================

[](#routing-library-for-php)

This library allows you to create static or dynamic routes. This library was inspired by [PHP Slim framework](https://www.slimframework.com/)

[![PHP Tests](https://github.com/gigili/PHP-routing/actions/workflows/php-pest-tests.yml/badge.svg)](https://github.com/gigili/PHP-routing/actions/workflows/php-pest-tests.yml)[![License](https://camo.githubusercontent.com/359009c69ba69e094e755fecd18668f4cd1e9fadd4a855be3e5768f497e828b1/68747470733a2f2f706f7365722e707567782e6f72672f6761632f726f7574696e672f6c6963656e7365)](https://packagist.org/packages/gac/routing)[![Total Downloads](https://camo.githubusercontent.com/d3c699ad827d85b9b8ab46b1aa36955da424d797791062425e0d03bd297800de/68747470733a2f2f706f7365722e707567782e6f72672f6761632f726f7574696e672f646f776e6c6f616473)](https://packagist.org/packages/gac/routing)

Install via composer
--------------------

[](#install-via-composer)

```
composer require gac/routing
```

Manual install
--------------

[](#manual-install)

Download the latest release from the [Releases page](https://github.com/gigili/PHP-routing/releases).

Don't forget to add these `include_once` statements to your php files:

```
include_once "./Exceptions/CallbackNotFound.php";
include_once "./Exceptions/RouteNotFoundException.php";
include_once "./Request.php";
include_once "./Routes.php";
```

Post install
------------

[](#post-install)

To use this library properly you will need to create a `.htaccess` file at the root of the project.

Example of the `.htaccess` file would look like this:

```
RewriteEngine On

RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

RewriteRule ^(.+)$ index.php [QSA,L]
```

### Note

[](#note)

If you've named your main file differently, replace `index.php` in the `.htaccess` file with whatever your main application file is.

Quick start
-----------

[](#quick-start)

Sample code to allow you to quickly start with your development.

```
use Gac\Routing\Exceptions\CallbackNotFound;
use Gac\Routing\Exceptions\RouteNotFoundException;
use Gac\Routing\Request;
use Gac\Routing\Response;
use Gac\Routing\Routes;

include_once "vendor/autoload.php"; # IF YOU'RE USING composer

$routes = new Routes();
try {
    $routes->add('/', function (Request $request) {
        // Old way of doing it, still supported until v4
        $request
            ->status(200, "OK")
            ->send(["message" => "Welcome"]);

        // New way of doing it
        Response::
        withHeader("Content-Type", "application/json")::
        withStatus(200, 'OK')::
        withBody([ "message" => "Welcome" ])::
        send();
    });

    $routes->route('/', function (Request $request) {
        // Old way of doing it, still supported until v4
        $request
            ->status(200, "OK")
            ->send(["message" => "Welcome"]);

        // New way of doing it
        Response::
        withHeader("Content-Type", "application/json")::
        withStatus(200, 'OK')::
        withBody([ "message" => "Welcome" ])::
        send();
    }, [Routes::POST])->save();

    $routes->route();
} catch (RouteNotFoundException $ex) {
    // Old way of doing it, still supported until v4
    $routes->request->status(404, "Route not found")->send(["error" => ["message" => $ex->getMessage()]]);

    // New way of doing it
    Response::withStatus(404, 'Route not found')::send(["error" => [ "message" => $ex->getMessage() ]]);
} catch (CallbackNotFound $ex) {
    // Old way of doing it, still supported until v4
    $routes->request->status(404, "Callback not found")->send(["error" => ["message" => $ex->getMessage()]]);

    // New way of doing it
    Response::withStatus(404, 'Callback not found')::send(["error" => [ "message" => $ex->getMessage() ]]);
} catch (Exception $ex) {
    $code = $ex->getCode() ?? 500;

    // Old way of doing it, still supported until v4
    $routes->request->status($code)->send(["error" => ["message" => $ex->getMessage()]]);

    // New way of doing it
    Response::withStatus($code)::send(["error" => [ "message" => $ex->getMessage() ]]);
}
```

Examples
--------

[](#examples)

### Dynamic routes example

[](#dynamic-routes-example)

```
$routes->add('/test/{int:userID}-{username}/{float:amount}/{bool:valid}', function (
    Request $request,
    int $userID,
    string $username,
    float $amount,
    bool $valid
) {
    echo 'Dynamic route content here';
});
```

### Chained routes

[](#chained-routes)

When using chained methods either use `->save()` or `->add()` as the last method to indicate the end of a chain

**NOTE**

- `->save(true|false)` method can still be chained onto if needed
    - Passing `false` (the default value is `true`) to the `->save()` method will preserve all the previous prefixes and middlewares in that chain
- `->add()` **CAN NOT** be chained onto and should be the last call in chain

```
$routes
    ->prefix('/user') // all the routes added will have the /user prefix
    ->middleware([ 'verify_token' ]) // all the routes added will have the verify_token middleware applied
    ->route('/', [ HomeController::class, 'getUsers' ], Routes::GET)
    ->route('/', [ HomeController::class, 'addUser' ], Routes::POST)
    ->route('/', [ HomeController::class, 'updateUser' ], Routes::PATCH)
    ->route('/', [ HomeController::class, 'replaceUser' ], Routes::PUT)
    ->add('/test', [ HomeController::class, 'deleteUser' ], Routes::DELETE);
```

#### Chained routes with save at the end

[](#chained-routes-with-save-at-the-end)

```
$routes
    ->prefix("/test")
    ->middleware(['decode_token'])
    ->route("/t0", function(Request $request){})
    ->get("/t1", function (){})
    ->post("/t2", function (){})
    ->put("/t3", function (){})
    ->patch("/t4", function (){})
    ->delete("/t5", function (){})
    ->save();
```

#### Chained routes with multiple chains in one call

[](#chained-routes-with-multiple-chains-in-one-call)

```
$routes
    ->prefix("/test")
    ->middleware([ 'decode_token' ])
    ->get("/t1", function () { }) // route would be: /test/t1
    ->get("/t2", function () { }) // route would be: /test/t2
    ->get("/t3", function () { }) // route would be: /test/t3
    ->save(false) // by passing the false argument here, we keep all the previous shared data from the chain (previous prefix(es) and middlewares)
    ->prefix("/test2")
    ->middleware([ "verify_token" ])
    ->get("/t4", function () { }) // route would be: /test/test2/t4
    ->get("/t5", function () { }) // route would be: /test/test2/t5
    ->get("/t6", function () { }) // route would be: /test/test2/t6
    ->save() // by not passing the false argument here, we are removing all shared data from the previous chains (previous prefix(es) and middlewares)
    ->prefix("/test3")
    ->middleware([ "verify_token" ])
    ->get("/t7", function () { }) // route would be: /test3/t7
    ->get("/t8", function () { }) // route would be: /test3/t8
    ->get("/t9", function () { }) // route would be: /test3/t9
    ->add(); //using save or add at the end makes the chaining stop and allows for other independent routes to be added
```

### Passing arguments to middleware methods

[](#passing-arguments-to-middleware-methods)

When working with middlewares you can also pass them arguments if you need to

```
use Gac\Routing\Response;

$routes
    ->middleware([
        'test_middleware',
        'has_roles' => 'admin,user',
        [ Middleware::class, 'test_method' ],
        [ Middleware::class, 'has_role', 'Admin', 'Moderator', [ 'User', 'Bot' ] ],
    ])
    ->add('/test', function (Request $request) {
        // Old way of doing it, still supported until v4
        $request->send([ 'msg' => 'testing' ]);

        //New way of doing it
        Response::send([ "msg" => "testing" ]);
    });
```

Every middleware function can also accept an argument of type `Gac\Routing\Request` at any position as long as it has the proper type specified.

### Optional parameters

[](#optional-parameters)

```
$routes->add(
    '/demo/{id?}',
    function($id = 'defaultValue'){
    	echo "ID: . $id";
    },
    Routes::GET
);
```

When calling this endpoint with `/demo` it will output `ID: defaultValue` and with `/demo/123` it will output `ID: 123`

### Dependency injection on route classes

[](#dependency-injection-on-route-classes)

When using classes to handle your route callback, and those classes have some dependencies that need to be injected through a constructor, you can specify them as an array of arguments to be injected or let the library try to auto-inject classes.

```
$routes->add(
    '/demo',
    [
        HomeController::class,
        'dependency_injection_test',
        [ new InjectedClass() ]
    ],
    Routes::GET
);
```

You can also use named arguments or mix and match them

```
$routes->add(
    '/demo',
    [
        HomeController::class,
        'dependency_injection_test',
        [ "injected_var" => new InjectedClass(), new Middleware ]
    ],
    Routes::GET
);
```

Letting the library auto-inject classes into the constructor

```
$routes->add(
    '/demo',
    [ InjectController::class ],
    Routes::GET
);
```

**NOTE**

The library will always try to auto-inject classes (***will skip ones with null as default value***) if non are provided, and you're using a class for callbacks.

### Use `__invoke` instead for single method classes

[](#use-__invoke-instead-for-single-method-classes)

```
$routes->add(
    '/invoke',
    [ HomeController::class ],
    Routes::GET
);
```

You can also use `__invoke` with dependency injection as well:

```
$routes->add(
    '/invoke',
    [
        HomeController::class,
        [ new InjectedClass() ]
    ],
    Routes::GET
);
```

For more examples look in the [sample folder](/sample) `index.php` file

Documentation
-------------

[](#documentation)

Source code documentation can be found at [PHP Routing documentation](https://gigili.github.io/PHP-routing/) page

Features
--------

[](#features)

- Static routes
- Dynamic routes
- Dynamic routes with optional parameters
- Middlewares
    - Pass arguments to middlewares
- Route prefixes
- Method chaining
- Dependency injection on classes
    - Manual injection
    - Auto-injection

###  Health Score

35

—

LowBetter than 80% of packages

Maintenance24

Infrequent updates — may be unmaintained

Popularity22

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity69

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

Recently: every ~27 days

Total

32

Last Release

633d ago

Major Versions

v1.0.12 → v2.0.02021-04-07

v2.0.7 → v3.0.02021-10-26

### Community

Maintainers

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

---

Top Contributors

[![gigili](https://avatars.githubusercontent.com/u/2153382?v=4)](https://github.com/gigili "gigili (174 commits)")

---

Tags

dependency-injectionhacktoberfestlibrarymiddlewarenavigationphprouterroutingmiddlewareapiroutingroutelibray

###  Code Quality

TestsPest

### Embed Badge

![Health badge](/badges/gac-routing/health.svg)

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

###  Alternatives

[nezamy/route

Route - Fast, flexible routing for PHP, enabling you to quickly and easily build RESTful web applications.

21436.6k5](/packages/nezamy-route)[shahghasiadil/laravel-api-versioning

Elegant attribute-based API versioning solution for Laravel applications with built-in deprecation management and version inheritance

2913.6k](/packages/shahghasiadil-laravel-api-versioning)

PHPackages © 2026

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