{"id":22627526,"url":"https://github.com/rammewerk/router","last_synced_at":"2025-09-08T02:33:58.153Z","repository":{"id":182939948,"uuid":"655892491","full_name":"rammewerk/router","owner":"rammewerk","description":"Lightweight PHP 8.4+ router with class-based routing, type-safe parameters and middleware. Minimal, fast, and flexible for modern PHP apps.","archived":false,"fork":false,"pushed_at":"2025-02-03T14:48:02.000Z","size":454,"stargazers_count":15,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-23T08:16:33.433Z","etag":null,"topics":["http","router"],"latest_commit_sha":null,"homepage":"https://rammewerk.com","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rammewerk.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-06-19T20:41:56.000Z","updated_at":"2025-02-06T08:13:51.000Z","dependencies_parsed_at":"2025-02-03T12:29:34.814Z","dependency_job_id":"efbd0cee-3106-4053-a1ea-9c42c2c9a16c","html_url":"https://github.com/rammewerk/router","commit_stats":null,"previous_names":["rammewerk/router"],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rammewerk%2Frouter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rammewerk%2Frouter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rammewerk%2Frouter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rammewerk%2Frouter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rammewerk","download_url":"https://codeload.github.com/rammewerk/router/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248464272,"owners_count":21108238,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["http","router"],"created_at":"2024-12-09T01:12:10.990Z","updated_at":"2025-04-11T18:51:42.325Z","avatar_url":"https://github.com/rammewerk.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"Rammewerk Router\n====\n\nRammewerk Router is a **lightweight**, **high-performance PHP router** designed for modern applications. It prioritizes\n**fast\nroute resolution, minimal overhead**, and a straightforward setup. Built for **PHP 8.4**, it takes a modern, class-based\napproach while remaining flexible and powerful in its minimalism.\n\nWith **minimal configuration** required, Rammewerk Router is **easy to set up** while still offering a wide range of\nfeatures\nlike type-safe parameters, dependency injection, and middleware. It provides **just the right amount of structure**\nwithout\nunnecessary complexity - delivering performance and flexibility in a simple, intuitive package.\n\n#### Key Features:\n\n- **Class-Based Routing**: Organize routes cleanly and intuitively.\n- **Attribute-Based Routing**: Define routes directly in classes and methods for a clean, declarative approach.\n- **Type-Safe Parameters**: Smart detection of route dependencies and parameters.\n- **Middleware Support**: Add functionality like authentication or logging.\n- **Minimal Yet Powerful**: Focused on simplicity while offering the flexibility you need.\n\n## Table of Contents\n\n- [Project Goals](#-project-goals)\n- [Getting started](#-getting-started)\n    - [Install](#install)\n    - [Requirements](#requirements)\n    - [Usage](#usage)\n- [Basic Routing](#-basic-routing)\n- [Class-based Routing](#-class-based-routing)\n    - [Define Subpaths with Class Methods](#define-subpaths-with-class-methods)\n    - [Dynamic Path Segments](#dynamic-path-segments)\n    - [Wildcard parameters](#wildcard-parameters)\n    - [Parameter class dependencies](#parameter-class-dependencies)\n    - [Binding a Path to a Specific Method](#binding-a-path-to-a-specific-method)\n    - [Wrapping Up Class-Based Routing](#wrapping-up-class-based-routing)\n- [Dependency Injection](#-dependency-injection)\n- [Middleware](#-middleware)\n    - [Request Handling](#request-handling)\n    - [Group Middleware](#group-middleware)\n    - [Wrapping Up Middleware](#wrapping-up-middleware)\n- [Dispatching and Response](#-dispatching-and-response)\n- [Method-Specific Request Handling](#-method-specific-request-handling)\n- [Powerful Parameter Handling](#-powerful-parameter-handling)\n- [Performance and Speed](#-performance-and-speed)\n- [Closure-Based Routes](#-closure-based-routes)\n- [PSR-7 \u0026 PSR-15 Support](#-psr-7--psr-15-support)\n- [Route Attributes](#-route-attributes)\n- [Benchmark](#-benchmark)\n\n## 🎯 Project Goals\n\nThese goals reflect what Rammewerk strives to achieve across all its components:\n\n- **Lightweight \u0026 Fast**: Small, focused and compact library with zero bloat, built for speed.\n- **Plug-and-Play**: Works out of the box with minimal configuration.\n- **Minimal \u0026 Understandable**: Simple code that’s easy to read, adapt, and even rewrite for your own projects.\n- **Flexible by Design**: Add your own implementations and customize it to suit your needs.\n- **Open for Collaboration**: Fork it, explore it, and contribute back with pull requests!\n\nBy using Rammewerk, you get a minimal yet powerful foundation that’s easy to build on and improve. Let’s dive in! 🔧✨\n\n## 🚀 Getting Started\n\n### Install\n\nInstall Rammewerk Router via composer:\n\n```bash\ncomposer require rammewerk/router\n```\n\n### Requirements\n\n- Requires PHP 8.4+.\n- Server must route all requests to a single PHP file (e.g., index.php) using Caddy, Nginx, or Apache.\n- Use a Dependency Injection container like [Rammewerk Container](https://github.com/rammewerk/container) for managing\n  class instances.\n\n### Usage\n\n```php\nuse Rammewerk\\Router\\Router;\n\n// Define your dependency resolver.\n// This is a closure that receives a class string\n// and  must return an instance of that class.\n$di_container = static fn( string $class) =\u003e new $class() );\n\n// Create Router\n$router = new Router($di_container);\n\n// Define routes\n// ...\n\n// Go!\n$response = $router-\u003edispatch();\n\n// Handle response....\n\n```\n\n## 🧭 Basic Routing\n\nWhile the Rammewerk Router is designed for class-based routing, it also supports closures.\n\nHere’s a simple example:\n\n```php\n$router-\u003eadd('/hello', function() {\n    return 'Hello World!';\n});\n```\n\nThis matches `/hello`, triggers the closure, and returns “Hello World!”\n\n## 🏗️ Class-based Routing\n\nClass-based routing is the core feature of Rammewerk Router. It maps paths and their nested routes directly to a class,\nmaking it both powerful and flexible.\n\nHere’s how it works:\n\n```php\n$router-\u003eadd('/profile', ProfileRoute::class);\n```\n\nWith this setup, the `ProfileRoute` class will handle all requests to `/profile` (and its sub-paths, unless overridden\nby other routes).\n\nHere’s an example of a simple class for the `/profile` path:\n\n```php\nnamespace Routes;\n\nclass ProfileRoute {\n\n    public function index(): string {\n        return 'You visited /profile';\n    }\n\n}\n```\n\nThe `index()` method is the default handler for the base path of a class-based route. In this case, accessing `/profile`\ntriggers the `index()` method.\n\nYou can also define class routes with a single `__invoke()` method. This will be called if no other method matches or is\ndefined. The `__invoke()` method is best used when the class doesn’t have additional route methods, keeping it simple\nand focused.\n\n### Define Subpaths with Class Methods\n\nTo handle a path like `/profile/settings/notifications`, simply add a method to your class matching the subpath\nstructure:\n\n```php\nclass ProfileRoute {\n\n    // Previous methods\n\n    public function settings_notifications(): string {\n        return 'You visited /profile/settings/notifications';\n    }\n\n}\n```\n\n### Route attributes as alternative\n\nYou can also use the `#[Route]` if you prefer a more declarative approach:\n\n```php\nuse Rammewerk\\Router\\Foundation\\Route;\n\n#[Route('/profile')] // \u003c-- must match based path given in add()\nclass ProfileRoute {\n\n    // Will match /profile/settings/notifications\n    #[Route('/settings/notifications')] // \u003c-- Attribute\n    #[Route('/profile/settings/notifications')] // \u003c-- This also works\n    public function notifications(): string {\n        return 'You visited /profile/settings/notifications';\n    }\n    \n}\n```\n\nEach segment after the base path (`/profile`) maps to a method, with subpath segments replaced by underscores (`_`).\n\n### Dynamic Path Segments\n\nYou can define dynamic subpaths by adding parameters to your method:\n\n```php\nclass ProfileRoute {\n\n    public function edit( int $id ): string {\n        return \"You visited /profile/edit/$id\";\n    }\n    \n}\n```\n\nAccessing `/profile/edit/123` triggers the `edit()` method with the parameter `$id` = `123`.\n\n### Wildcard parameters\n\nAdditionally, you can use wildcard parameters (`*`) to map subpaths to parameters. For example, handling\n`/profile/123/edit` can be done like this:\n\n```php\n$router-\u003eadd('/profile/*/edit', ProfileEditRoute::class);\n```\n\nWildcard parameters are mapped in order, alongside subpaths. For example, `/profile/123/edit/notification` results in\nparameters `123` and `notification`.\n\n## Parameter types\n\n- Parameter names don’t matter, but their order does.\n- If a parameter isn’t in the path, it must be **optional** or **nullable** to match.\n- Type hints are supported, and path segments are converted to match (`int`, `float`, `bool`, `string`). Undefined or\n  mixed defaults to string.\n- Parameters that can't convert to defined type are rejected, and route won't match.\n- Paths must match exactly. For example, `/profile/edit/123` won’t match `/profile/edit/123/something`.\n- Use a variadic parameter (`...$args`) to allow extra subpaths to match.\n\n#### Enums\n\nYou can use both PHP backed enumerations and regular enums as route parameters because Rammewerk will convert them\nautomatically based on the given path argument.\n\n```php\n# Backed enum\nenum OrderStatusEnum: string {\n    case OPEN = 'open'; // Path Argument /open/ will match this\n    case CLOSED = 'closed'; // Path Argument /closed/ will match this\n}\n\n# Regular enum\nenum OrderShipmentEnum {\n    case SHIPPED;   // Path Argument /shipped/ will match this\n    case NOT_SHIPPED; // Path Argument /not_shipped/ will match this\n}\n\n# Example:\n\n#[Route('/orders')]\nclass Orders {\n\n    #[Route('/item/*/status')] // Will support paths like: /item/123/status/open\n    public function itemStatus( int $item_id, OrderStatusEnum $status ): string {\n        return \"The status for item $item_id is $status-\u003evalue\";\n    }\n     \n}\n```\n\nThe router will automatically convert the parameter to the type specified in the method signature.\n\n### Parameter class dependencies\n\nYou can use classes as parameters, and the router will resolve them via the dependency handler set during\ninitialization:\n\n```php\nclass ProfileRoute {\n    public function edit( Profile $profile, Template $template, int $id ): Response {\n        $user = $profile-\u003efind($id);\n        return $template-\u003erender('profile/edit', [$user]);\n    }\n}\n```\n\nThe order of class dependencies doesn’t matter, but parameters extracted from the path must be in the correct order.\n\n### Binding a Path to a Specific Method\n\nYou can bind a route to a specific class method in its class by defining the method in the route definition:\n\n```php\n$router-\u003eadd(...)-\u003eclassMethod('edit');\n```\n\nThis ensures the `edit()` method of the `ProfileRoute` class is always called when `/profile/settings` is accessed.\n\n### Wrapping Up Class-Based Routing\n\nLess configuration? Checked! 🎉 Class-based routing keeps things straightforward. Adding new routes is as easy as\ndefining methods in your handler\nclasses. With type safety, support for required and optional parameters, and the flexibility of wildcards, you can build\nroutes that adapt to your needs without unnecessary complexity.\n\n---\n\n## 📦 Dependency Injection\n\nTo manage dependencies for class-based and closure-based routes, as well as middleware, the router requires a dependency\nresolver. You *must* set this up during initialization by passing a closure to the constructor. This closure receives a\nclass name and returns an instance of that class.\n\n\u003e For a simple and efficient solution, check out [Rammewerk Container](https://github.com/rammewerk/container).\n\n```php\n$router = new Router( static fn( string $class_string ) =\u003e $container-\u003ecreate($class_string) );\n```\n\nThis approach keeps your routes clean and ensures seamless dependency handling.\n\n## 🛡️ Middleware\n\nMiddleware adds functionality to your routes, like authentication, logging, or caching, without cluttering your route\nclasses. It acts as a layer that processes requests before they reach your route handler or modifies responses\nafterward.\n\nHere’s how to add middleware to a route:\n\n```php\n$router-\u003eadd('/', HomeRoutes::class)-\u003emiddleware([\n    AuthMiddleware::class,\n    LoggerMiddleware::class,\n]);\n```\n\nMiddleware runs in the order it’s defined. Each middleware must have a handle method that processes the request and\ncalls the next closure to continue:\n\n```php\nclass AuthMiddleware {\n    public function handle(Request $request, \\Closure $next) {\n        // Do auth stuff\n        return $next($request);\n    }\n}\n```\n\n**Note**: Even though the request object is optional (`object|null`), your middleware must define it as the first\nparameter of the `handle()` method. The `handle()` method **must always** receive two arguments: the given request\nobject (or\nnull) and the next closure to call.\n\n\u003e Rammewerk Router also supports PSR-15 MiddlewareInterface. See [PSR-15 Support](#-psr-7--psr-15-support) for more\n\u003e information.\n\n### Request Handling - Dispatching\n\nThe router passes a request object to each middleware and the route handler. The request type is flexible; you can\npass any object during dispatch:\n\n```php\n$router-\u003edispatch('/profile', new ServerRequest());\n```\n\nWhile optional, it’s good practice to type-hint the request in your handle method and ensure it matches the request\nclass passed during dispatch.\n\n\u003e Rammewerk Router also supports PSR-7 ServerRequestInterface. See [PSR-7 Support](#-psr-7--psr-15-support) for more\n\n### Group Middleware\n\nUse the `group()` method to apply middleware to multiple routes at once. This keeps your code clean and avoids\nrepetitive middleware declarations.\n\nHere’s an example:\n\n```php\n$router-\u003egroup(function(Router $r) {\n    $r-\u003eadd('/products', ProductRoutes::class);\n    $r-\u003eadd('/users', fn() =\u003e 'Users listing');\n})-\u003emiddleware([\n    AuthMiddleware::class,\n    LoggerMiddleware::class\n]);\n```\n\nIn this example, both `/products` and `/users` routes share the same middleware (`AuthMiddleware` and\n`LoggerMiddleware`), applied in the defined order.\n\nIf you define middleware on a route inside the group, it will run **before** the group’s middleware:\n\n```php\n$r-\u003egroup(function (Router $r) {\n    $r-\u003eadd('/products', ProductRoutes::class)-\u003emiddleware([AuthMiddleware::class]);\n    // More routes\n})-\u003emiddleware([LoggerMiddleware::class]);\n```\n\nHere, `AuthMiddleware` runs first for `/products`, followed by `LoggerMiddleware` from the group. This lets you control\nthe middleware order for each route.\n\n### Wrapping Up Middleware\n\nLittle configuration? Checked! 🎉 Middleware in the router is flexible and straightforward, letting you add layers to\nyour routes without overcomplicating things. You’re free to implement middleware however you like — no restrictions on\nwhich request class to use or how to handle it.\n\n---\n\n## 🚀 Dispatching and Response\n\nDispatching routes is simple: just call the dispatch method on your router instance.\n\n```php\ntry {\n    $response = $router-\u003edispatch( path: '/', serverRequest: $request );\n    // Handle response\n} catch (InvalidRoute $e) {\n    // Handle 404 errors or log unmatched paths\n} catch (Throwable $e) {\n    // Handle other application errors, or let it bubble up\n}\n```\n\n- The path parameter is matched against your routes. If no match is found, an InvalidRoute exception is thrown, letting\n  you handle 404s or similar responses.\n- The request parameter is optional and passes a request object to middleware and route handlers for processing.\n- The response is returned from the dispatch method, which can be any type. It’s up to you to handle it in your\n  application.\n\n## 🚦 Method-Specific Request Handling\n\nThis router doesn’t predefine request types like `GET` or `POST`. It simply passes any request to the route. If you want\nto implement a `get()`/`post()`/`delete()` style structure, you can achieve it by adding a wrapper or using middleware\nto handle specific request methods. This gives you full flexibility to define request handling as you see fit.\n\n## 🧩 Powerful Parameter Handling\n\nThis router shines with its robust and flexible parameter system:\n\n- **Type-safe \u0026 Intuitive**: Supports type hints, union types, and automatic conversion for seamless parameter handling.\n- **Dependency-Friendly**: Reflects parameters in methods and closures, allowing seamless integration with your own DI\n  container for maximum flexibility and adaptability.\n- **Wildcard Simplicity**: Use * to capture dynamic segments - no regex needed, and parameter types ensure effortless\n  refactoring and clarity.\n- **No Dictated Names**: Parameters don’t rely on specific names, giving you freedom and flexibility.\n- **Support for Enums**: Support for both backed enums and regular enums. Backed enums are automatically converted to\n  it's type, where the given parameter argument is called with ::tryFrom(), while regular enums are matched with their\n  case.\n\nThis level of type safety, combined with flexible wildcards, is rare in other routers. It’s designed to make routing\nboth powerful and effortless! 🚀\n\n## ⚡ Performance and Speed\n\nRammewerk Router is designed to stay lean and move fast.\n\n1. It uses simple arrays to store routes and quickly narrows down\n   matching paths by comparing only relevant segments.\n2. Regex patterns are sorted by length so more specific routes are\n   tested first.\n3. Reflection is only performed once a route is confirmed, so there’s no overhead for routes that don’t match\n4. With minimal internal complexity, no bulky dependencies, and a single-file core, the router focuses on doing one job\n   well without slowing you\n   down in production.\n\n\u003e Integrating [Rammewerk Container](https://github.com/rammewerk/container) can boost speed even more, thanks to its\n\u003e lazy-loading approach. It’s also one of the fastest DI containers out there, as shown in benchmarks.\n\n## 🪶 Closure-Based Routes\n\nWhile class-based routing is the core feature of Rammewerk Router, closure-based routes can be useful for simple,\nstandalone handlers or quick prototypes.\n\nThese routes still benefit from the same powerful parameter handling as\nclass-based routes, including dependency injection of classes and type-hinted subpath parameters. Middleware can also be\napplied seamlessly to closure-based routes, ensuring consistent behavior across your application.\n\nHere’s an example:\n\n```php\n// Define a closure-based route with parameter handling and middleware\n$router-\u003eadd('/greet', function (string $name, Logger $logger): string {\n  $logger-\u003einfo(\"Greeting user: $name\");\n  return \"Hello, $name!\";\n})-\u003emiddleware([\n    AuthMiddleware::class,\n]);\n\n// Dispatch the router\n$router-\u003edispatch('/greet/John', new Request());\n```\n\nKey Points:\n\n- **Parameter Handling**: Subpath parameters like {name} are automatically resolved and type-checked.\n- **Dependency Injection**: Classes like Logger are injected via the resolver.\n- **Middleware**: Layers such as AuthMiddleware can be applied, ensuring functionality like authentication or logging is\n  handled consistently.\n\nClosure-based routes provide a lightweight yet flexible alternative when you don’t need a dedicated class handler.\n\n## 🌐 PSR-7 \u0026 PSR-15 Support\n\nThe **Rammewerk Router** includes an extended class, `PsrRouter`, designed specifically for applications requiring\n**PSR-7** (HTTP Message Interface) and **PSR-15** (Middleware and Request Handlers) compliance. Use PsrRouter as a\ndrop-in replacement for the default Router when working with PSR-compliant middleware and request handlers.\n\n#### Highlights\n\n- **PSR-7**: Pass compliant ServerRequestInterface objects to handlers and middleware.\n- **PSR-15**: Add reusable, standards-based MiddlewareInterface layers.\n- **Pipeline**: Middleware is executed sequentially, ensuring proper request and response processing.\n\nHere's an example of PSR-7 \u0026 PSR-15 Usage:\n\n```php\nuse Rammewerk\\Router\\Extension\\PsrRouter;\n\n$router = new PsrRouter(static fn(string $class) =\u003e $container-\u003eget($class));\n\n// Add PSR middleware and routes\n// HomeRoute handle method must return a PSR-7 ResponseInterface\n$router-\u003eadd('/home', HomeRoute::class)-\u003emiddleware([\n    AuthMiddleware::class, // Implements PSR-15 MiddlewareInterface\n]);\n\n// $serverRequest is a PSR-7 ServerRequestInterface\n$response = $router-\u003edispatch('/', $serverRequest);\n\nheader('Content-Type: ' . $response-\u003egetHeaderLine('Content-Type'));\necho $response-\u003egetBody();\n```\n\nThe PsrRouter not only provides PSR-7 and PSR-15 support but also serves as an example of how to extend the Rammewerk\nRouter to implement custom solutions tailored to specific application needs. This showcases the flexibility of the\nRammewerk Router’s architecture, enabling developers to adapt it to various standards or unique requirements.\n\n\u003e **NOTE:** If your project requires `getAttribute()` or similar functionality to handle parameters directly, the\n\u003e Rammewerk Router might not be the ideal solution for your needs. This router is designed for flexibility and handles\n\u003e parameters differently, with logic tailored to its specific architecture. If you’re looking for a router that supports\n\u003e named parameters or simpler routing logic, you may want to consider alternatives that are more closely aligned with\n\u003e your\n\u003e project’s requirements.\n\n\nHere’s an updated section for your README documentation to reflect the usage and rules for Route attributes:\n\n## 🛠 Route Attributes\n\nThe `#[Route]` attribute allows you to define routes directly on classes and methods for a clean and declarative\napproach to routing.\n\n**Class-Level Route Attribute:**\n\n- The `#[Route]` attribute **must** be defined on the class level.\n- The route path in the class attribute **must** match the base segment provided in the `add()` method. If not, the\n  class\n  will not be reflected for route attributes. This ensures faster reflection and avoids ambiguity.\n\n```php\nuse Rammewerk\\Router\\Foundation\\Route;\n\n#[Route('/dashboard')]\nclass DashboardRoute {\n    // ...\n}\n\n// Base segment ('/dashboard') matches class-level #Route('/dashboard')\n$router-\u003eadd('/dashboard', DashboardRoute::class); \n```\n\n**Method-Level Route Attribute:**\n\n- Use `#[Route]` attributes on methods to define subroutes. These routes follow the same wildcard (`*`) and trailing\n  parameters logic as manually defined routes.\n- The parameters for wildcard and trailing segments are passed to the method for validation and handling, just like we\n  do on closures and class-based routing, described above.\n\n```php\n#[Route('/dashboard')]\nclass DashboardRoute {\n\n    #[Route('/stats/*/details')]\n    public function stats(string $param1, string ...$wildcards): Response {\n        // Example: `/dashboard/stats/123/details/flag1/flag2`\n    }\n\n    #[Route('/profile')]\n    public function profile( int $id ): string {\n        return \"Profile page for user ID $id\";\n    }\n    \n    public function unknown(): string {\n        return 'Will never be called, no matching route found';\n    }\n    \n}\n```\n\n#### Why This Approach?\n\n- **Performance**: The router only reflects classes if the base segment matches the class-level route attribute. This\n  ensures faster processing and avoids unnecessary computation.\n- **Clarity**: Explicitly linking class-level routes to base segments keeps the logic predictable and easy to debug.\n- **Flexibility**: You can use wildcards and trailing parameters to build dynamic and flexible route patterns.\n\n## 🏃 Benchmark\n\nRammewerk Router is designed for speed and minimal overhead, ensuring fast route resolution even in complex scenarios.\n\nThis benchmark test was conducted on **PHP 8.4 CLI**, calling a **PHP-FPM server with opcache enabled** via curl. Each\nrouter was **warmed up** before testing to ensure a fair comparison.\n\n#### Benchmark Setup:\n\n- **150 different routes** with a mix of **simple and complex** paths, including a **dynamic parameter**.\n- Each route was called **500 times**, totaling **75,000 route resolutions per test**.\n- The **median time** was recorded after **30 test runs** for each package.\n\n| Rank | Container            | Time (ms) | Time (%) | Peak Memory (MB) | Peak Memory (%) |\n|------|----------------------|-----------|----------|------------------|-----------------|\n| 1    | **Rammewerk Router** | 79.959    | 100%     | 1.287            | 100%            |\n| 2    | **FastRoute**        | 175.513   | 220%     | 0.788            | 61%             |\n| 3    | **PHRoute**          | 192.192   | 240%     | 0.937            | 73%             |\n| 4    | **Symfony Router**   | 491.643   | 615%     | 0.817            | 64%             |\n\n#### Key Takeaways:\n\n- **Rammewerk Router outperformed all tested routers** in this scenario, offering **more than twice the speed of\n  FastRoute** and\n  significantly faster execution than Symfony Router.\n- **Memory usage was slightly higher** compared to some alternatives, but the trade-off resulted in substantial\n  performance\n  gains.\n- FastRoute showed competitive results when handling a small number of different routes, performing slightly better in\n  such cases.\n- Rammewerk Router particularly excels in complex routing scenarios, maintaining high efficiency even with numerous\n  route variations.\n\nMore extensive benchmarks and detailed performance tests will be available in a dedicated GitHub repository soon. 🚀","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frammewerk%2Frouter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frammewerk%2Frouter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frammewerk%2Frouter/lists"}