PHPackages                             mindplay/walkway - 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. [Utility &amp; Helpers](/categories/utility)
4. /
5. mindplay/walkway

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

mindplay/walkway
================

Elegant, modular router for PHP

3.0.0(10y ago)442115[1 issues](https://github.com/mindplay-dk/walkway/issues)LGPL-3.0+PHPPHP &gt;=5.3.0

Since May 2Pushed 9y ago6 watchersCompare

[ Source](https://github.com/mindplay-dk/walkway)[ Packagist](https://packagist.org/packages/mindplay/walkway)[ RSS](/packages/mindplay-walkway/feed)WikiDiscussions master Synced 2w ago

READMEChangelog (3)Dependencies (3)Versions (9)Used By (0)

Walkway
-------

[](#walkway)

Elegant, modular routing for PHP - inspired by [vlucas](https://github.com/vlucas)/[bulletphp](https://github.com/vlucas/bulletphp).

Supports [PHP-DI](http://php-di.org/), [Aura.DI](https://github.com/auraphp/Aura.Di), [Unbox](https://github.com/mindplay-dk/unbox) and [many other](https://github.com/container-interop/container-interop#compatible-projects)DI containers via [container-interop](https://github.com/container-interop/container-interop).

[![PHP Version](https://camo.githubusercontent.com/3defa515920750802a17f1973ac80f3f8d2f03f68b58fd1dfe672528243bfa21/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d352e332532422d626c75652e737667)](https://packagist.org/packages/mindplay/walkway)[![Build Status](https://camo.githubusercontent.com/46df2c312af0dac36646bf0c64ff055eb12753ad2d3c114221d6586cd90277fb/68747470733a2f2f7472617669732d63692e6f72672f6d696e64706c61792d646b2f77616c6b7761792e706e67)](https://travis-ci.org/mindplay-dk/walkway)[![Code Coverage](https://camo.githubusercontent.com/ff58d026df408f546157e56b8019684219c259a0c925f3b293db02aced021342/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f6d696e64706c61792d646b2f77616c6b7761792f6261646765732f636f7665726167652e706e67)](https://scrutinizer-ci.com/g/mindplay-dk/walkway/)[![Scrutinizer Code Quality](https://camo.githubusercontent.com/fc15970a462cc212e1b6673807c2e6b94ec8fd217a57c6347f1b408dffd1686d/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f6d696e64706c61792d646b2f77616c6b7761792f6261646765732f7175616c6974792d73636f72652e706e67)](https://scrutinizer-ci.com/g/mindplay-dk/walkway/)

Note that this is not a framework, and not a micro-framework - this library exclusively deals with routing, and deliberately does not provide any kind of front-controller, request/response or controller/action abstraction, error-handling, or any other framework-like feature.

This makes the library very open-ended - you can use the routing facility to route whatever you want (anything that resembles a path) to whatever you want. (e.g. controllers, other scripts, another framework or CMS, anything.)

Unlike most routers using this style/approach, this router is functional - which means the routes are actually being defined as the resolver "walks" them, one level at a time, which is practically inifinitely scalable.

This router is also modular - which means that a set of routes can be self-contained, and can be reused, which further helps with scalability in applications with a large number of routes, since modules that aren't visited while resolving a route, won't be loaded or initialized at all.

The codebase is very small, very simple, and very open-ended - you can do both good and evil with this library.

To understand how to make the most of it, please read the documentation below.

Defining Routes
===============

[](#defining-routes)

This is the fun part!

You define patterns by using array-syntax to configure callback-functions, which may define nested sub-patterns, and so on.

A collection of Routes is called a Module - you can create an instance and configure it to handle a path like `'hello/world'` using code like this:

```
$module = new Module;

$module['hello'] = function (Route $route) {
    $route['world'] = function (Route $route) {
        $route->get = function() {
            echo 'Hello, World!';
        };
    };
};
```

Route patterns are (PCRE) regular expressions - you can use substring capture, combined with a function, to define route parameters:

```
$module['archive'] = function(Route $route) {
    $route['-'] = function (Route $route) {
        $route->get = function ($year, $month) {
            echo "Archive for $month / $year";
        };
    };
};
```

Note that the expression `-` is pre-processed, and internally is transformed into the PCRE regular expression `(?\d+)-(?\d+)`, which isn't quite as legible.

Modules can (optionally) pre-process the patterns - the default patterns allow you to use the simplified pattern syntax shown above, and recognizes a few symbols like `int`and `slug`, which are just named abbreviations for regular expression patterns. You can add or remove pre-processing functions, as needed.

Modules
=======

[](#modules)

To make a reusable Module, you can derive your own specialized class from Module - which also gives you a natural location for URL creation-functions:

```
class HelloWorldModule extends Module
{
    public function init()
    {
        parent::init();

        $this['hello'] = function (Route $route) {
            $route['world'] = function (Route $route) {
                $route->get = function() {
                    echo 'Hello, World!';
                };
            };
        };
    }

    public function hello_url($world = 'world')
    {
        return "/hello/$world";
    }
}
```

Encapsulating routes in a Module also provides modularity - to delegate control from one Module to another, call the delegate() method on the Route object:

```
$route['comments'] = function (Route $route) {
    $route->delegate(new CommentModule());
};
```

See the "test.php" script for an example of creating and routing to a nested Module.

Note that there's a good reason why URL-creation is not part of this library - this is explained at the end of this document.

Evaluating Routes
=================

[](#evaluating-routes)

A Module is the root of a set of Routes.

To resolve a path and find the Route defined by your Module, do this:

```
$route = $module->resolve('archive/2012-08');
```

Note that this would return `null` if the route was unresolved.

To execute an HTTP method-handler associated with the Route, do this:

```
$result = $route->execute('GET');
```

The returned `$result` is whatever you choose to return in your handler, which could be a Controller or HTML content, or nothing - if you prefer to simply output your content directly, and you don't issue a return-statement, the return-value is boolean `true` or `false`, indicating success or failure.

Model / View / Controller
=========================

[](#model--view--controller)

The `execute()` method in the previous example returns `true` on success, unless the HTTP method-handler itself returns something else. In the example above, the HTTP method-handlers do not provide return values, but you can implement a simple MVC-style controller/action-abstraction without using a framework:

```
$module['posts'] = function ($route) {
    $controller = new PostsController();

    $route[''] = function (Route $route) use ($controller) {

        $route->get = function ($post_id) use ($controller) {
            return $controller->showPost($post_id);
        };

        $route['edit'] = function (Route $route) use ($controller) {
            $route->get = function ($post_id) use ($controller) {
                return $controller->editPost($post_id);
            };
            $route->post = function ($post_id) use ($controller) {
                return $controller->updatePost($post_id);
            };
        };
    };
};

$result = $module->resolve('posts/42/edit')->execute('get');
```

Container Integration
=====================

[](#container-integration)

If you wish to integrate with a dependency injection container, you may implement [InvokerInterface](src/InvokerInterface.php) and inject your own invoker via the optional constructor argument to [Module](src/Module.php).

An invoker is [provided](src/InteropInvoker.php) to enable direct integration with a [variety](https://github.com/container-interop/container-interop#compatible-projects)of DI containers via [container-interop](https://github.com/container-interop/container-interop).

If you have a service-container or some other framework/application component that needs to be easily accessible from within your routes, while avoiding the need for `use()` clauses down through the hierarchy of functions, you can insert values into `Route::$vars` during `init()` (or at any point) - this collection stores values captured while resolving a route, and these values are used to inject function-arguments for both route-definitions and action-methods.

IDE Support
===========

[](#ide-support)

To get full IDE support with auto-complete and static analysis, make sure your code uses type-hints - for example:

```
$this['hello'] = function (Route $route) {
    $route->_ // create('show_archive', array('year' => '2013', 'month' => '04));
```

With the following real beauty:

```
$url = $module->show_archive_url('2013', '04');
```

The latter is half the amount of typing, it's easier to read - an IDE can provide auto-completions, and you can perform inspections (static analysis) on the code if you have to change the name or parameters.

Also, because this is a real function, and not some kind of abstraction, you can use whatever code is necessary to create URLs, create different URLs under different circumstances, use arguments of different types (even entities, if needed), and so on.

The advantages of URL creation being free from the limitations of even the best, most complex abstractions, are too numerous to ignore - plus, at the end of the day, try to view URL creation for what it really is: a string template. You're creating a *string*. Do you really need a framework for that? Simple solutions for simple problems, please!

Creating a simple Front Controller
==================================

[](#creating-a-simple-front-controller)

You can [use Walkway as middleware](https://gist.github.com/mindplay-dk/11e7c08ff6aa4d3486a4)with [Conduit](https://github.com/phly/conduit).

To use Walkway as a bare-bones front-controller, create an "index.php" file along the lines of:

```
// get the path and HTTP request method:

$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$method = $_SERVER['REQUEST_METHOD'];

// create your module and resolve the path:

$router = new YourAwesomeModule();

$route = $router->resolve($path);

// generate a 404 if the path did not resolve:

if ($route->$method === null) {
    header("HTTP/1.0 404 No Route");
}

// dispatch the get/head/post/put/delete function:

$result = $route->execute($method);

// optionally do something clever with $result here...
```

Then create an ".htaccess" file to route incoming requests to your "index.php":

```
RewriteEngine on

# if a directory or a file exists, use it directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

# otherwise forward it to index.php
RewriteRule . index.php

```

And you're set!

Enjoy!
======

[](#enjoy)

Feedback and pull requests welcome :-)

###  Health Score

33

—

LowBetter than 72% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity24

Limited adoption so far

Community14

Small or concentrated contributor base

Maturity63

Established project with proven stability

 Bus Factor1

Top contributor holds 97.1% 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 ~138 days

Recently: every ~168 days

Total

8

Last Release

3880d ago

Major Versions

0.9.0 → 1.0.02014-02-18

1.0.2 → 2.0.02014-11-16

2.0.2 → 3.0.02015-12-30

### Community

Maintainers

![](https://www.gravatar.com/avatar/9445f567f43ee7a963270651e40e533634586f959e4df3d5398d001b1cb49be8?d=identicon)[mindplay.dk](/maintainers/mindplay.dk)

---

Top Contributors

[![mindplay-dk](https://avatars.githubusercontent.com/u/103348?v=4)](https://github.com/mindplay-dk "mindplay-dk (66 commits)")[![higoka](https://avatars.githubusercontent.com/u/16455725?v=4)](https://github.com/higoka "higoka (2 commits)")

### Embed Badge

![Health badge](/badges/mindplay-walkway/health.svg)

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

###  Alternatives

[anthonymartin/geo-location

Powerful GeoCoding library: Retrieve bounding box coordinates, distances between geopoints, point in polygon, get longitude and latitude from addresses and more with GeoLocation for PHP

1881.0M12](/packages/anthonymartin-geo-location)

PHPackages © 2026

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