windwalker/uri
A PHP URI library for parsing, building, and manipulating URLs and URIs. Create immutable URI objects, resolve relative references, handle query strings and fragments, and normalize paths with a clean, standards-aware API.
Architecture fit
windwalker/uri is a standalone PSR-7 UriInterface implementation plus a Uri helper class for string-level URL manipulation. Laravel's request layer is Symfony HttpFoundation, not PSR-7, so there is no natural insertion point in the framework's request lifecycle. The package only fits where a PSR-7 boundary already exists: PSR-18 clients, PSR-15 middleware, third-party SDKs that type-hint Psr\Http\Message\UriInterface, or signed-URL/callback construction in domain services.
Critically, PSR-7 is a contract—any compliant implementation is functionally interchangeable. There is no differentiator here, so the real question isn't "does it fit?" but "is this the cheapest compliant implementation to own in a Laravel stack?" Based on the signals below, it is not: guzzlehttp/psr7 already arrives transitively with Laravel's HTTP client, and league/uri is the de facto standard for URI manipulation in the Symfony/Laravel ecosystem.
Integration feasibility
Installation is mechanically simple (MIT, PSR-4, no service provider, no config), but the gate is the psr/http-message constraint. psr/http-message 2.0 added return types to the interface; older Windwalker builds target ^1.0. Contemporary Laravel 10/11 stacks routinely resolve ^1.1 || ^2.0. Expect either a hard conflict or a pin that drags in an old release and an old PHP floor. Validate with composer require windwalker/uri --dry-run and composer why-not windwalker/uri before any design work. Note also that a PSR-7 Uri alone is insufficient for request/response bridging—you will still need a stream implementation and PSR-17 factories.
Technical risk
[READ ONLY], which reads as a read-only/archived repository. Confirm on GitHub; if true, there are no future security patches or PHP-version compatibility fixes.ventoviro/windwalker-uri while the Composer name is windwalker/uri—the project has been rebranded/migrated at least once, which historically correlates with install-path breakage.UriInterface mandates precise normalization: percent-encoding rules, default-port elision, empty-path vs. /, userinfo encoding, IPv6 literals, IDN. This is exactly where lightly exercised implementations break, and the bugs surface as wrong redirect targets or signature mismatches rather than exceptions.Key questions
Uri at all, versus plain URL string manipulation?composer.lock via Guzzle? If so, what does this package add?php-http/*, http-interop)?league/uri does not replicate?Stack fit
Laravel → Symfony HttpFoundation → no PSR-7. If a PSR-7 boundary is genuinely required, the idiomatic pairing is symfony/psr-http-message-bridge + nyholm/psr7 (plus psr/http-factory), or guzzlehttp/psr7 since Illuminate's HTTP client already depends on Guzzle. Introducing a second PSR-7 implementation into the same process is an anti-pattern: two UriInterface implementations are not interchangeable for factory injection or instanceof checks, and the bridge binds to exactly one.
Migration path
If adopted despite the above, confine it. Define App\Support\Uri\UriFactory (or a small UriValue object) that returns your abstraction, and let exactly one file reference Windwalker\Uri\*. Everything else—controllers, jobs, domain services—depends on your interface. Swap cost then becomes one class plus one Composer line, which is the only thing that makes an unmaintained dependency tolerable.
Compatibility
Verify against your floor: PHP constraint (8.1/8.2/8.3), psr/http-message constraint, absence of global helper functions, and absence of class-name collisions under php-scoper prefixing (relevant if you ship a prefixed build). There is no Laravel service provider to register—confirm that remains true, since an auto-discovered provider would couple you to framework internals.
Sequencing
league/uri or Laravel's UrlGenerator + Str. No PSR-7 required.windwalker/uri only if a hard constraint rules that out.cweagans/composer-patches hook for fixes, register a removal ticket with a date, and gate usage behind the adapter module.Maintenance A read-only upstream means you are the maintainer. The cost is not code volume—the package is small—but the recurring tax of proving it still installs on every PHP and Composer upgrade, plus the absence of a security-advisory channel. MIT permits a fork, but forking a URI parser means owning a URI parser, including its conformance edge cases.
Support
No vendor support, negligible community footprint, and almost no StackOverflow or blog coverage. Every on-call engineer encountering it will need a written explanation of why it exists. Contrast with league/uri (actively maintained, Symfony-adjacent, well documented) or guzzlehttp/psr7 (massive install base, effectively free support via search).
Scaling Runtime scaling is a non-issue: URI parsing is stateless, in-memory, microsecond-scale, with no I/O and no connection pooling concerns. The scaling risk is dependency-graph scaling—each added PSR-7 implementation multiplies the chance of type mismatches at boundaries and adds a line item to every future security audit and SBOM review.
Failure modes
psr/http-message bump. High likelihood, breaks CI rather than production, but blocks security patching of unrelated packages.Ramp-up
The API surface is small—hours to learn, not days. The real onboarding cost is social: the team must be convinced the choice is defensible, and future maintainers must be handed a written rationale for "why not league/uri." Absent a compelling, documented constraint, that rationale does not exist.
Recommendation: Do not adopt. If the requirement is URL manipulation, use league/uri; if it is PSR-7 interop, use the implementation already present via Guzzle (or nyholm/psr7 for bridging). The only defensible adoption scenario is a hard external contract requiring a PSR-7 UriInterface that no existing dependency satisfies—and even then, isolate it behind an adapter with a scheduled removal.
How can I help you explore Laravel packages today?