====== PHP RFC: ext/uri followups ====== * Version: 0.1 * Date: 2025-10-17 * Author: Máté Kocsis, kocsismate@php.net * Status: Draft * Target version: PHP 8.5 * Implementation: https://github.com/kocsismate/php-src/pull/9 ===== Introduction ===== This RFC proposes a follow-up to the [[rfc:url_parsing_api|URL Parsing API RFC]], extending the ''URI'' and ''URL'' classes with additional capabilities for constructing, analyzing, and manipulating URIs. The goal is to provide a more complete and developer-friendly API for URI handling, consistent with both the WHATWG URL Standard and RFC 3986. ===== Proposal ===== The following new functionality is introduced in this proposal: - URI builder - Query string manipulation - Retrieving/modifying path segments as an array - Retrieving the host type - Determining if the URL is "special" (per WHATWG) - Dedicated percent-encoding/decoding support ---- ==== URI Builder ==== A fluent API is introduced for programmatically constructing and modifying URIs: $uri = (new UriBuilder()) ->scheme('https') ->host('example.com') ->path('/foo/bar') ->query(['a' => 1, 'b' => 2]) ->fragment('section1') ->build(); echo $uri; // "https://example.com/foo/bar?a=1&b=2#section1" This builder makes URI creation and modification easier and less error-prone than manually concatenating strings or repeatedly invoking ''Uri::with*()'' methods. **Design goals:** * Immutable ''Uri'' objects as the result * Chainable fluent syntax * Automatic percent-encoding of each component * Validation of scheme, host, and port consistency ---- ==== Query String Manipulation ==== ''Uri'' and ''Url'' classes now expose ''getQueryParams()'' / ''setQueryParams()'' methods for working directly with parsed query parameters: $uri = new Uri('https://example.com/?foo=bar&x=1'); $params = $uri->getQueryParams(); $params['y'] = '2'; $uri = $uri->withQueryParams($params); echo $uri->getQuery(); // "foo=bar&x=1&y=2" A dedicated ''UriQuery'' helper object also offers a structured interface similar to JavaScript’s ''URLSearchParams''. ---- ==== Path Segments as an Array ==== ''getPathSegments()'' and ''withPathSegments()'' provide convenient access to the path component as an array: $uri = new Uri('https://example.com/foo/bar/baz'); $segments = $uri->getPathSegments(); // ['foo', 'bar', 'baz'] $uri = $uri->withPathSegments(['a', 'b']); echo $uri->getPath(); // "/a/b" This is useful for frameworks and routers that manipulate paths dynamically. ---- ==== Host Type Detection ==== The new ''getHostType()'' method returns the type of the host component: $uri = new Uri('https://192.168.0.1/'); echo $uri->getHostType(); // UriHostType::IPv4 $uri = new Uri('https://[2001:db8::1]/'); echo $uri->getHostType(); // UriHostType::IPv6 $uri = new Uri('https://example.com/'); echo $uri->getHostType(); // UriHostType::Domain Possible return values include: * ''UriHostType::Domain'' * ''UriHostType::IPv4'' * ''UriHostType::IPv6'' * ''UriHostType::Opaque'' * ''UriHostType::None'' ---- ==== Determining if a URL is Special ==== The WHATWG URL Standard defines *special* schemes (''http'', ''https'', ''ftp'', ''file'', ''ws'', ''wss''), which have distinct parsing and serialization rules. The new ''isSpecial()'' method allows checking this: $url = new Url('https://example.com'); var_dump($url->isSpecial()); // true $url = new Url('custom:example'); var_dump($url->isSpecial()); // false This enables low-level control for applications that need to mirror WHATWG behaviors in parsing or normalization. ---- ==== Percent-Encoding and Decoding ==== Dedicated static methods provide precise control over percent-encoding and decoding according to RFC 3986 rules: Uri::encodeComponent('a b'); // "a%20b" Uri::decodeComponent('a%20b'); // "a b" These utilities respect the character sets defined in RFC 3986 and may later be extended to support ''application/x-www-form-urlencoded'' semantics as used in HTML forms. ---- ===== Backward Incompatible Changes ===== None. All APIs are additive and live in the ''Uri'' / ''Url'' namespaces without changing existing behavior. ===== Proposed PHP Version(s) ===== PHP 8.6 ===== RFC Impact ===== ==== To the Ecosystem ==== What effect will the RFC have on IDEs, Language Servers (LSPs), Static Analyzers, Auto-Formatters, Linters and commonly used userland PHP libraries? ==== To Existing Extensions ==== Will existing extensions be affected? ==== To SAPIs ==== Describe the impact to CLI, Development web server, embedded PHP etc. ===== Open Issues ===== Make sure there are no open issues when the vote starts! ===== Future Scope ===== This section should outline areas that you are not planning to work on in the scope of this RFC, but that might be iterated upon in the future by yourself or another contributor. This helps with long-term planning and ensuring this RFC does not prevent future work. ===== Voting Choices ===== * Yes * No * Abstain ===== Patches and Tests ===== https://github.com/kocsismate/php-src/pull/9 ===== Implementation ===== After the RFC is implemented, this section should contain: - the version(s) it was merged into - a link to the git commit(s) - a link to the PHP manual entry for the feature ===== References ===== Links to external references, discussions, or RFCs. ===== Rejected Features ===== Keep this updated with features that were discussed on the mail lists. ===== Changelog ===== If there are major changes to the initial proposal, please include a short summary with a date or a link to the mailing list announcement here, as not everyone has access to the wikis' version history.