israel-nogueira/fast-router

Classe para gerenciar as suas rotas no PHP com facilidade e segurança

Installs: 73

Dependents: 0

Suggesters: 0

Security: 0

Stars: 1

Watchers: 1

Forks: 1

Open Issues: 1

pkg:composer/israel-nogueira/fast-router

v2.0.0 2026-02-10 16:04 UTC

This package is auto-updated.

Last update: 2026-02-10 16:42:56 UTC


README

Latest Version Total Downloads License PHP Version

Modern, fast and flexible PHP router with support for static and instance modes, middleware chains, route groups, and advanced routing features.

✨ Features

  • Dual Mode: Static (auto-dispatch) and Instance (manual control)
  • Route Parameters: Simple {id} and regex {id:\d+} with optional parameters
  • Route Groups: Nested groups with prefix and middleware inheritance
  • Middleware Chain: Elegant middleware system with dependency injection
  • Multiple HTTP Methods: GET, POST, PUT, DELETE, PATCH, OPTIONS, ANY, and custom
  • Controller Support: String syntax, array syntax, and closures
  • Named Routes: Reference routes by name (coming soon)
  • PSR-4 Autoloading: Modern namespace structure
  • Type Safety: Full PHP 8.1+ type hints
  • Zero Dependencies: Standalone library
  • Debug Mode: Built-in debugging capabilities

📦 Installation

composer require israel-nogueira/fast-router

Requirements

  • PHP >= 8.1
  • Composer

🚀 Quick Start

Basic Usage

<?php

require 'vendor/autoload.php';

use IsraelNogueira\FastRouter\Router;

// Simple route
Router::get('/', function() {
    echo "Hello World!";
});

// Route with parameter
Router::get('user/{id}', function($id) {
    echo "User ID: {$id}";
});

// POST route
Router::post('contact', function() {
    echo "Form submitted!";
});

📚 Documentation

Table of Contents

🔄 Static vs Instance Mode

Static Mode (Auto-Dispatch)

Routes are automatically dispatched after each definition:

use IsraelNogueira\FastRouter\Router;

Router::get('/', function() {
    echo "Home";
});

Router::get('about', function() {
    echo "About";
});

// No need to call dispatch() - routes auto-execute

Instance Mode (Manual Control)

For more control, create a Router instance:

$router = new Router();

$router->get('/', function() {
    echo "Home";
});

$router->get('about', function() {
    echo "About";
});

// Manually dispatch routes
$router->dispatch();

When to use each:

  • Static Mode: Simple applications, rapid prototyping
  • Instance Mode: Testing, multiple routers, advanced control

🎯 Route Parameters

Simple Parameters

Router::get('user/{id}', function($id) {
    echo "User: {$id}";
});

Router::get('post/{year}/{month}/{slug}', function($year, $month, $slug) {
    echo "Post: {$slug} from {$month}/{$year}";
});

Regex Constraints

// Only numbers
Router::get('product/{id:\d+}', function($id) {
    echo "Product: {$id}";
});

// Only lowercase letters and hyphens
Router::get('category/{slug:[a-z-]+}', function($slug) {
    echo "Category: {$slug}";
});

// Date pattern
Router::get('archive/{date:\d{4}-\d{2}-\d{2}}', function($date) {
    echo "Archive: {$date}";
});

Optional Parameters

// Single optional parameter
Router::get('blog/{id:\d+}[/{title}/]', function($id, $title = null) {
    echo "Blog: {$id}";
    if ($title) echo " - {$title}";
});

// Multiple optional parameters
Router::get('archive/{year:\d{4}}[/{month:\d{2}}[/{day:\d{2}}/]/]', 
    function($year, $month = null, $day = null) {
        echo "Archive: {$year}/{$month}/{$day}";
    }
);

Syntax Rules:

  • Required: {param} or {param:regex}
  • Optional: [/{param}/] with slashes inside brackets
  • Nested: [/{a}[/{b}/]/] for multiple optional params

📂 Route Groups

Simple Groups

Router::group('admin', function($router) {
    
    $router->get('dashboard', function() {
        echo "Admin Dashboard";
        // URL: /admin/dashboard
    });
    
    $router->get('users', function() {
        echo "Admin Users";
        // URL: /admin/users
    });
});

Nested Groups

Router::group('admin', function($router) {
    
    $router->group('products', function($router) {
        
        $router->get('list', function() {
            echo "Product List";
            // URL: /admin/products/list
        });
        
        $router->group('category', function($router) {
            
            $router->get('list', function() {
                echo "Category List";
                // URL: /admin/products/category/list
            });
        });
    });
});

Groups with Middleware

Router::group([
    'prefix' => 'admin',
    'middleware' => ['auth', 'admin']
], function($router) {
    
    $router->get('dashboard', function() {
        echo "Secure Dashboard";
    });
    
    $router->get('settings', function() {
        echo "Secure Settings";
    });
});

🛡️ Middleware

Middleware allows you to filter HTTP requests before they reach your route handler.

Creating Middleware

class AuthMiddleware
{
    public function handle(array $returns, callable $next): mixed
    {
        // Check authentication
        if (!isset($_SESSION['user'])) {
            http_response_code(401);
            die('Unauthorized');
        }
        
        // Add data to returns array
        $returns[] = [
            'middleware' => 'auth',
            'user' => $_SESSION['user']
        ];
        
        // Continue to next middleware
        return $next($returns);
    }
}

Using Middleware

On Single Routes

Router::get([
    'prefix' => 'dashboard',
    'middleware' => [AuthMiddleware::class]
], function() {
    echo "Protected Dashboard";
});

On Route Groups

Router::group([
    'prefix' => 'admin',
    'middleware' => [AuthMiddleware::class, LogMiddleware::class]
], function($router) {
    
    $router->get('users', function() {
        echo "Admin Users";
    });
    
    $router->get('settings', function() {
        echo "Admin Settings";
    });
});

String Syntax

Router::get([
    'prefix' => 'profile',
    'middleware' => ['App\Middleware\Auth@handle']
], function() {
    echo "User Profile";
});

Middleware Chain

Middlewares execute in order. Each middleware must call $next($returns) to continue:

class FirstMiddleware
{
    public function handle(array $returns, callable $next): mixed
    {
        echo "Before First\n";
        $result = $next($returns);
        echo "After First\n";
        return $result;
    }
}

class SecondMiddleware
{
    public function handle(array $returns, callable $next): mixed
    {
        echo "Before Second\n";
        $result = $next($returns);
        echo "After Second\n";
        return $result;
    }
}

// Output:
// Before First
// Before Second
// [Route Handler]
// After Second
// After First

Stopping the Chain

To stop execution, don't call $next():

class AdminCheckMiddleware
{
    public function handle(array $returns, callable $next): mixed
    {
        if (!$this->isAdmin()) {
            http_response_code(403);
            die('Forbidden');
            // Chain stops here
        }
        
        return $next($returns);
    }
}

🎮 Controllers

Controller Class

class UserController
{
    public function index()
    {
        echo "User List";
    }
    
    public function show($id)
    {
        echo "User: {$id}";
    }
    
    public function store()
    {
        echo "Create User";
    }
}

String Syntax

Router::get('users', 'UserController@index');
Router::get('users/{id}', 'UserController@show');
Router::post('users', 'UserController@store');

Array Syntax

Router::get('users', [UserController::class, 'index']);
Router::get('users/{id}', [UserController::class, 'show']);
Router::post('users', [UserController::class, 'store']);

Multiple Callbacks

Execute multiple callbacks in sequence:

Router::get('dashboard', [
    'logRequest',  // Function
    'UserController@auth',  // Controller method
    [DashboardController::class, 'index'],  // Array syntax
    function() {  // Closure
        echo " - Rendered";
    }
]);

RESTful Resource Routes

$resource = 'posts';
$controller = PostController::class;

Router::get($resource, [$controller, 'index']);           // GET /posts
Router::get("{$resource}/create", [$controller, 'create']); // GET /posts/create
Router::post($resource, [$controller, 'store']);          // POST /posts
Router::get("{$resource}/{id}", [$controller, 'show']);   // GET /posts/123
Router::get("{$resource}/{id}/edit", [$controller, 'edit']); // GET /posts/123/edit
Router::put("{$resource}/{id}", [$controller, 'update']); // PUT /posts/123
Router::delete("{$resource}/{id}", [$controller, 'destroy']); // DELETE /posts/123

🌐 HTTP Methods

Standard Methods

Router::get('/', fn() => 'GET');
Router::post('/', fn() => 'POST');
Router::put('/', fn() => 'PUT');
Router::delete('/', fn() => 'DELETE');
Router::patch('/', fn() => 'PATCH');
Router::options('/', fn() => 'OPTIONS');
Router::head('/', fn() => 'HEAD');

Any Method

Accepts all HTTP methods:

Router::any('search', function() {
    echo "Works with any HTTP method";
});

Multiple Specific Methods

// Using math() method
Router::math(['GET', 'POST'], 'form', function() {
    if ($_SERVER['REQUEST_METHOD'] === 'GET') {
        echo "Show form";
    } else {
        echo "Process form";
    }
});

Custom Methods

Router::addRoute(['CUSTOM', 'SPECIAL'], 'endpoint', function() {
    echo "Custom HTTP method";
});

🔧 Advanced Features

Continue to Next Route

By default, router stops after first match. To continue:

Router::get([
    'prefix' => 'log/{id}',
    'continue' => true
], function($id) {
    error_log("Logging access to: {$id}");
});

Router::get('log/{id}', function($id) {
    echo "Viewing log: {$id}";
});

Debug Mode

Enable debugging to see route matching process:

$router = new Router();
$router->debug(true);

$router->get('test', function() {
    echo "Test";
});

$router->dispatch();

// Output includes HTML comments:
// <!-- Fast Router Debug -->
// <!-- Method: GET -->
// <!-- URL: /test -->
// <!-- Routes: 1 -->
// <!-- Matched: test -->

Custom Dispatch

Test routes with custom URL and method:

$router = new Router();

$router->get('api/users/{id}', function($id) {
    return ['user_id' => $id];
});

// Dispatch with custom parameters
$result = $router->dispatch('GET', '/api/users/123');

Route Collection

Access registered routes:

$router = new Router();

$router->get('home', fn() => 'Home');
$router->get('about', fn() => 'About');

$collection = $router->getRoutes();
echo "Total routes: " . $collection->count();

foreach ($collection->all() as $route) {
    echo $route->pattern . "\n";
}

Clear Routes

$router = new Router();

$router->get('test1', fn() => 'Test 1');
$router->get('test2', fn() => 'Test 2');

// Clear all routes
$router->clear();

🧪 Testing

Unit Testing Example

use PHPUnit\Framework\TestCase;
use IsraelNogueira\FastRouter\Router;

class RouterTest extends TestCase
{
    public function testBasicRoute()
    {
        $router = new Router();
        
        $router->get('test', function() {
            return 'success';
        });
        
        $result = $router->dispatch('GET', '/test');
        
        $this->assertEquals('success', $result);
    }
    
    public function testRouteParameters()
    {
        $router = new Router();
        
        $router->get('user/{id:\d+}', function($id) {
            return $id;
        });
        
        $result = $router->dispatch('GET', '/user/123');
        
        $this->assertEquals('123', $result);
    }
}

📖 Migration from v1.x

Breaking Changes

  1. Namespace change: IsraelNogueira\fastRouterIsraelNogueira\FastRouter
  2. PHP requirement: Now requires PHP 8.1+
  3. Type hints: All methods now use strict types

Migration Steps

// OLD (v1.x)
use IsraelNogueira\fastRouter\router;

router::get('/', function() {});

// NEW (v2.x)
use IsraelNogueira\FastRouter\Router;

Router::get('/', function() {});

Good news: All public APIs remain compatible! Just update the namespace.

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Development Setup

git clone https://github.com/israel-nogueira/fast-router.git
cd fast-router
composer install

Running Tests

composer test

Code Quality

composer analyse

📄 License

This project is licensed under the GPL-3.0-or-later License - see the LICENSE file for details.

👤 Author

Israel Nogueira

🌟 Show Your Support

Give a ⭐️ if this project helped you!

📝 Changelog

v2.0.0 (2026-02-10)

  • ✨ Complete refactoring with modern PHP 8.1+ features
  • ✨ Added strict type hints throughout
  • ✨ Improved middleware system
  • ✨ Better error handling with custom exceptions
  • ✨ PSR-4 autoloading structure
  • ✨ Debug mode
  • 🐛 Fixed various edge cases in route matching
  • 📚 Complete documentation rewrite

v1.x

  • Initial releases with basic routing functionality

Made with ❤️ by Israel Nogueira