PHPackages                             fruit/routekit - 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. fruit/routekit

ActiveLibrary[Framework](/categories/framework)

fruit/routekit
==============

fast router of fruit framework

2.0.3(5y ago)141PHPPHP ^7CI failing

Since Oct 22Pushed 5y ago1 watchersCompare

[ Source](https://github.com/fruit-php/routekit)[ Packagist](https://packagist.org/packages/fruit/routekit)[ RSS](/packages/fruit-routekit/feed)WikiDiscussions master Synced today

READMEChangelogDependencies (10)Versions (11)Used By (0)

RouteKit
========

[](#routekit)

This package is part of Fruit Framework, requires PHP 7.

RouteKit is a fast router implementation. It stores your routing rules in a tree structure, and you can make it even faster by generating a router class with builtin class generator.

[![Build Status](https://camo.githubusercontent.com/94336618b735a2dec072b2ef17333642d9d37c9632061f9543e87647e65c4a58/68747470733a2f2f7472617669732d63692e6f72672f526f6e6d692f66727569742d726f7574656b69742e737667)](https://travis-ci.org/Ronmi/fruit-routekit)

Synopsis
--------

[](#synopsis)

```
$mux = new Fruit\RouteKit\Mux;

// Create routing rules

$mux->get('/', array('MyClass', 'myMethod'));
// static method
$mux->get('/', 'Foo::Bar');
// function
$mux->get('/', 'foobar');
$mux->get('/', foobar);
// create handler/controller instance with constructor arguments.
$mux->get('/foo', array('MyClass', 'myMethod'), array('args', 'of', 'constructor'));

class FOO {
    public function BAR($arg1, $arg2){}
    public function BAZ($arg1, $arg2){}
}
// uri variables are unnamed, ":x" is identical to ":"
$mux->get('/foo/:/:x/bar', array('FOO', 'BAR'));
$mux->get('/foo/:1/baz/:2', array('FOO', 'BAZ'));

// you cannot use closure as handler
// $mux->get('/', function(){});    // wrong!

// but you can use object if it can be serialized with var_export()
$mux->get('/', array(new FOO, 'BAR'));

// dispatch request
$mux->dispatch($_SERVER['REQUEST_METHOD'], $_SERVER['PATH_INFO']);

// generate class
file_put_content('router.php', $mux->compileFile());

// use generated router class
$mux = require('router.php');
$mux->dispatch('GET', '/foo/123/abc/bar'); // (new Foo())->BAR('123', 'abc');
$mux->dispatch('GET', '/foo'); // (new MyClass('args', 'of', 'constructor'))->myMethod();

// use injector to do DI tasks
function di($url, $obj, $method) {
    $obj->setDB($db);
}
$mux->setInjector('di');
$mux->get('/', array(new FOO, 'BAR'));
$mux->dispatch('GET', '/'); // $obj = new FOO; di('/', $obj, 'BAR'); $obj->BAR();

// auth middleware, implements by input filter
function checkAuth($method, $url, $cb, $params) {
    if (!authed()) {
        header('Location: /login');
        return 'login first';
    }
}
$mux->setFilters(['checkAuth'], []);
$mux->get('/', array(new FOO, 'BAR'));
$mux->dispatch('GET', '/'); // redirect to /login if not logged in

// CORS middleware, implements by output filter
function addCORS($result) {
    // few lines of code adding CORS headers here

    return $result;
}
$mux->setFilters([], ['addCORS']);
$mux->get('/', array(new FOO, 'BAR'));
$mux->dispatch('GET', '/'); // client will receive CORS header!

// Templating middleware
function handler() {
    // real codes

    return ['view' => 'index.tmpl', 'data' => $result];
}
function forgeView($result) {
    return Template::load($result['view'])->render($result['data']);
}
$mux->setFilters([], ['addCORS']);
$mux->get('/', 'handler');
$mux->dispatch('GET', '/');
```

Why fast
--------

[](#why-fast)

RouteKit gains performance in two ways: better data structure for rule-matching, and ability to convert dynamic call to static call.

### Matching process

[](#matching-process)

RouteKit store routing rules in tree structure, so the matching speed will not be affected by how many rules you have. In other words, the matching process has constant time complexity.

More further, in generated router, we use a Finite State Machine to do the matching process, eliminates all possible function calls. Function calls are much slower comparing to opcode actions (`if`, `switch`, assignments, arithmatic operations, etc.) and hashtable manuplating. In practice, the FSM approach can run more than 20x faster comparing to array implementations.

### Static call

[](#static-call)

Most of router implementations splits the dispatching work into two pieces: matching with rules to grab correct handler, and execute it with cufa; And cufa is notorious for its **great** performance.

By generating custom router, we generate codes according to the information you provided in routing rules. No more cufa, no more reflection, so no more performance penalty.

Since codes are mostly generated using `var_export`, some cases are not supported:

- Classes cannot be restored using `__set_state`.
- Closures and anonymouse functions.
- Not accessible methods. (Methods not `public`)
- Special variables like resources.

Generated class should be thread-safe, since all properties and methods are static.

Type converting
---------------

[](#type-converting)

You can add type hintings to your handler, RouteKit will automatically do the type checking and converting for you. Currently we support only `int`, `float`, `bool` and `string`. We will not check/convert the parameters without type-hinted.

In non-compiled version, this is done by `ReflectionParameter::getType()`, so it would cost some performance for fetching reflection data.

In compiled version, we grab the type info at compile time, so there is no performance penalty excepts the type checking and converting works.

```
function handlerOK(int $i) {}
function handlerFAIL(array $i) {}
$mux->get('/ok/:', 'handlerOK');
$mux->get('/fail/:', 'handlerFAIL');

$mux->dispatch('GET', '/ok/1'); // works
$mux->dispatch('GET', '/ok/hello'); // throw a Fruit\RouteKit\TypeMismatchException
$mux->dispatch('GET', '/fail/1'); // throw an Exception with messages telling you array type is not supported
$mux->compile(); // throw an Exception with messages telling you array type is not supported
```

Injector and filter
-------------------

[](#injector-and-filter)

### Injectors

[](#injectors)

Injector is mean to solve "global variable" problem: you can *inject* global data into your handler object via the interface you defined.

### Input filters

[](#input-filters)

Input filter is mean to filter the control flow. Permission validating layer should be implemented here.

An input filter accepts exactly 4 parameters:

- HTTP method
- URL
- A callable represents the handler
- Array of parameters going to be passed to handler.

Returning anything other than `NULL` causes dispatching process to be interrupted, and the result of filtering is returned immediately.

While PHP syntax allowing you to modify the 4 params, you SHOULD NOT modify them. That's because input filter is not mean to filtering input data.

### Output filters

[](#output-filters)

Output filter is mean to filter the result. If you want to refine the result or HTTP headers, you're at the right place.

An output filter accepts only 1 prameter, which is the returned data from handler: you modify it, send or delete some headers, and return the result back. The most common example is adding CORS headers or forge real output by templating system.

Dispatching flow
----------------

[](#dispatching-flow)

1. Searching routing tree for currect handler and gather url parameters.
2. Executing input filters, decide whether to execute further.
3. If any input filter blocks execution, return immediately.
4. Modifying handler's internal state using injector.
5. Executes handler.
6. Manipulate result by executing output filters.

License
-------

[](#license)

Any version of MIT, GPL or LGPL.

###  Health Score

29

—

LowBetter than 57% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity9

Limited adoption so far

Community7

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

Recently: every ~187 days

Total

10

Last Release

2096d ago

Major Versions

1.1.3 → 2.0.02018-09-21

### Community

Maintainers

![](https://www.gravatar.com/avatar/1ef743a4ba2b41bc6643ca3c4d71f4608abee7dc617efa09b18e3fa0a44aeda8?d=identicon)[Ronmi](/maintainers/Ronmi)

---

Top Contributors

[![Ronmi](https://avatars.githubusercontent.com/u/59556?v=4)](https://github.com/Ronmi "Ronmi (68 commits)")

###  Code Quality

TestsPHPUnit

Code StylePHP\_CodeSniffer

### Embed Badge

![Health badge](/badges/fruit-routekit/health.svg)

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

###  Alternatives

[laravel/dusk

Laravel Dusk provides simple end-to-end testing and browser automation.

1.9k39.6M298](/packages/laravel-dusk)[nineinchnick/edatatables

Grid widget for the Yii Framework, wrapper for the DataTables jQuery plugin

173.2k](/packages/nineinchnick-edatatables)[link-cloud/fast-hyperf

LinkCloud Fast Hyperf

241.2k1](/packages/link-cloud-fast-hyperf)

PHPackages © 2026

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