PHPackages                             dlunire/dlroute - 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. dlunire/dlroute

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

dlunire/dlroute
===============

Sistema avanzado de enrutamiento HTTP impulsado por autómatas finitos. Altamente eficiente, flexible y de alto rendimiento. Úsalo como motor central de DLUnire o intégralo fácilmente en cualquier proyecto PHP.

v1.0.11(2w ago)1270↓90.6%1MITPHP

Since Apr 8Pushed 2w agoCompare

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

READMEChangelogDependencies (2)Versions (14)Used By (1)

DLRoute
=======

[](#dlroute)

✨ Sponsors
----------

[](#-sponsors)

Gracias a las siguientes personas y empresas por apoyar el desarrollo de **DLRoute** y la futura **v2.0.0** (autómatas puros).

### Patrocinadores Activos

[](#patrocinadores-activos)

---

**¿Quieres formar parte de esto?**

[❤️ Patrocíname en GitHub Sponsors](https://github.com/sponsors/dlunire)

---

DLRoute is not "another PHP router". It is a routing pipeline built on formal language theory — the same foundations used in compilers — applied to HTTP request dispatching for the first time in PHP.

```
composer require dlunire/dlroute
```

Requires **PHP 8.2+**. Works with any PHP project — with or without a framework.

---

Why DLRoute is different
------------------------

[](#why-dlroute-is-different)

Every other PHP router — FastRoute, Symfony Routing, Laravel Router — was built around one goal: map URLs to controllers as fast as possible. Matching was the problem. Everything else was secondary.

DLRoute was built around a different premise: **routing is a formal processing pipeline, not a lookup table.**

That premise produces an architecture that does not exist in any other PHP router.

---

What no other PHP router does
-----------------------------

[](#what-no-other-php-router-does)

### 1. Finite automaton querystring parser

[](#1-finite-automaton-querystring-parser)

Every other router uses `parse_str()` — a PHP function that has existed since PHP 4.

DLRoute replaces it with a finite automaton that processes the querystring **byte by byte in a single pass**, with explicit states (`QUERY_NAME` → `QUERY_VALUE`), emitting immutable typed DTOs with the exact byte offset of each token in the original string.

```
// GET /?campo=valor&activo
$params = (new QueryParamComposer())->get_query_params();

$params['campo']->value;         // "valor"
$params['campo']->offset;        // 0   — byte position of the name
$params['campo']->offset_value;  // 6   — byte position of the value
$params['campo']->length;        // 5

$params['activo']->value;        // null — parameter without value
```

No other PHP router exposes byte-level position metadata for querystring parameters.

---

### 2. Route syntax lexer with exact-position diagnostics

[](#2-route-syntax-lexer-with-exact-position-diagnostics)

When you define a route with invalid syntax, DLRoute does not throw a generic exception. The `RouterLexer` analyzes the route definition **character by character** and emits a fully actionable diagnostic:

```
// Invalid route
DLRoute::get('/{ciencia?=algo}/users', fn() => []);
```

```
RouteException: Expected closing brace (}) after «?» (position 9).
Received instead: «?=algo}/users».
Optional parameters must follow the format → «{param?}»
Route defined: «/{ciencia?=algo}/users»

```

Compare this to what Laravel does with an invalid HTTP method:

**Laravel** → silent `404 HTML page`

**DLRoute** → structured JSON with exact error, file, line, and stack trace

That is the difference between a system with formal contracts and one without.

---

### 3. Telemetry as a first-class citizen of the core

[](#3-telemetry-as-a-first-class-citizen-of-the-core)

`TelemetryRequest` lives in `DLRoute\Core\Telemetry` — not a middleware, not a plugin. It was designed from the start as part of the engine.

```
DLRoute::get('/{resource?}', function() {
    return TelemetryRequest::telemetry("My API");
});
```

```
{
    "message":     "My API",
    "route":       "/api/users",
    "uri":         "/api/users?filter=active",
    "base_url":    "https://my-domain.com",
    "domain":      "my-domain.com",
    "is_https":    true,
    "port":        443,
    "local_port":  80,
    "timestamp":   "2026-06-18T01:20:47+00:00",
    "cliente_ip":  "203.0.113.1",
    "method":      "GET",
    "proxy":       true,
    "query_param": {
        "filter": {
            "name":         "filter",
            "offset":       0,
            "value":        "active",
            "offset_value": 7,
            "length":       6
        }
    }
}
```

Single call. No configuration. Works correctly behind Cloudflare, Nginx reverse proxies, and tunnels — differentiating `port` (client-facing) from `local_port` (internal server port) automatically.

To achieve equivalent output in Laravel you need: Telescope + trusted proxy configuration + an external logging package.

---

### 4. Typed contracts in route registration

[](#4-typed-contracts-in-route-registration)

`Methods::GET` is an enum, not a string. The router validates the type **before registering the route**. If you pass something invalid, it fails immediately with a structured JSON error.

```
// ❌ Wrong
DLRoute::match(['david'], new RouteHandler(...));

// ✅ Correct
DLRoute::match([Methods::GET, Methods::POST], new RouteHandler(...));
```

```
{
    "status": false,
    "error": "DLRoute::match: Expected «DLRoute\\Enums\\Methods». Received «david» instead.",
    "details": { "filename": "...", "line": 200 }
}
```

Laravel silently responds with `404 HTML` for the same input.

---

### 5. Zero-configuration subdirectory detection

[](#5-zero-configuration-subdirectory-detection)

DLRoute calculates the real request path via **byte-position arithmetic** — no `str_replace()`, no regular expressions:

```
OFFSET = LENGTH(dir) - 1
route  = substr(uri, OFFSET)

```

Deterministic and O(1), regardless of whether the subdirectory name appears repeated in the URI.

```
{
    "route":    "/api/products",
    "uri":      "/subdir/subdir/api/products",
    "dir":      "/subdir/subdir",
    "base_url": "https://example.com/subdir/subdir"
}
```

---

Feature comparison
------------------

[](#feature-comparison)

CapabilityDLRouteFastRouteSymfony RouterLaravel RouterFinite automaton querystring parser✅❌❌❌Byte-level token position metadata✅❌❌❌Route syntax lexer with diagnostics✅❌❌❌Exact byte position on syntax errors✅❌❌❌Native telemetry in the core✅❌❌❌Structured JSON errors✅❌❌❌Typed HTTP method contracts (enum)✅❌❌❌Zero-config subdirectory detection✅❌❌❌Automatic JSON response from array✅❌❌❌Optional parameters natively✅❌❌workaroundExplicit MIME type per route✅❌❌❌Zero external dependencies✅✅❌❌---

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

[](#quick-start)

### 1. Project structure

[](#1-project-structure)

```
my-project/
├── public/
│   └── index.php
├── app/
│   └── Controllers/
│       └── ApiController.php
└── vendor/

```

### 2. Entry point

[](#2-entry-point)

```
