Re: [RFC] [Discussion] Followup Improvements for ext/uri

From: Date: Fri, 19 Dec 2025 07:59:38 +0000
Subject: Re: [RFC] [Discussion] Followup Improvements for ext/uri
References: 1 2 3 4 5 6 7  Groups: php.internals 
Request: Send a blank email to internals+get-129656@lists.php.net to get a copy of this message
On Thu, Dec 18, 2025 at 10:46 PM Máté Kocsis <kocsismate90@gmail.com> wrote: > Hi, > > The WHATWG URL living standard does the following: >> >> let url = new >> URL('https://example.com?debug&foo=bar&debug='); >> console.log( >> url.searchParams.toString(), //returns debug=&foo=bar&debug=' >> ); >> >> the pair gets converted to ['debug' => '']. The roundtrip does not >> conserve the query string as is but all key/pair (tuples) are present. >> > > Yes, confirmed. Unfortunately, WHATWG URL only supports string values, so > there's no way to support > query parameters without a key (e.g. ?debug) in the RFC implementation > either. :( > > On the other hand, the RFC 3986 implementation supports this notion, even > uriparser calls this out > in its documentation: > > https://uriparser.github.io/doc/api/latest/index.html#querystrings. > > However, there are a few other problems which came up when I was updating > my implementation. > > 1.) Yesterday, I wrote that name mangling of the query params shouldn't > happen. However, as I realized, > it is still needed for non-list arrays, because the [..] suffix must be > added to their name: > > $params = new Uri\Rfc3986\UriQueryParams() > ->append("foo", [2 => "bar", 4 => "baz"]); > > echo $params->toRfc3986String(); // > foo%5B2%5D=bar&foo%5B4%5D=baz > > var_dump($params->getFirst("foo")); // NULL > > Even though I appended params with the name "foo", no items can be > returned when calling getFirst(), > because of name mangling. > > 2.) I'm not really sure how empty arrays should be represented? PHP > doesn't retain them, and they are > simply skipped. But should we do the same thing? I can't really come up > with any other sensible behavior. > > $params = new Uri\Rfc3986\UriQueryParams() > ->append("foo", []); > > echo $params->toRfc3986String(); // ??? > > 3.) We wrote earlier that objects shouldn't be supported when creating > the query string from variables. But what about > backed enums? Support for them in http_build_query() was added not long > ago: https://github.com/php/php-src/pull/15650 > Should we support them, right? > > Regards, > Máté > > Hi Máté 1.) Yesterday, I wrote that name mangling of the query params shouldn't > happen. However, as I realized, it is still needed for non-list arrays, because the [..] suffix must be > added to their name: When I talk about data mangling I am talking about this parse_str('foo.bar=baz', $params); var_dump($params); //returns ['foo_bar' => 'baz'] The bracket is a PHP specificity and I would not change it now otherwise you introduce a huge BC break in the ecosystem for no particular gain IMHO. 2.) I'm not really sure how empty arrays should be represented? PHP doesn't > retain them, and they are > simply skipped. But should we do the same thing? I can't really come up > with any other sensible behavior. > $params = new Uri\Rfc3986\UriQueryParams() > ->append("foo", []); This to me should yield the same result as ->append('foo', null); as the array construct is only indicative of a repeating parameter name if there is no repeat then it means no data is attached to the name. 3.) We wrote earlier that objects shouldn't be supported when creating > the query string from variables. But what about > backed enums? Support for them in http_build_query() was added not long > ago: https://github.com/php/php-src/pull/15650 > Should we support them, right? This gave me a WTF? moment (sorry for the language). Why was this change added in PHP without a proper discussion in the internals or even an RFC because it sets up a lot of precedence and even changes how http_build_query is supposed to work in regards to objects. If this had landed on the internal list I would have objected to it on the ground as it breaks expectation in the function handling of type in PHP. Do I agree with everything the function does ? No, but introducing inconsistencies in the function is not a good thing. Now http_build_query is aware of specific objects. Sringable or Travarsable objects are not detected but Enum are ?? Pure Enum emits a TypeError but resource do not ? Backed Enums are not converted to int or to string by PDO ? Why would http_build_query do it differently ? The same reasoning apply as to why Backed Enum does not have a Stringable interface. Yes the output was "weird" in PHP8.1-> PHP8.3 but it was expected. Should something be done for DateInterval too because the output using http_build_query is atrocious ? I still stand on my opinion that objects, resources should NEVER be converted. In an ideal world only scalar + null and their repeated values encapsulated in an array should be allowed; everything else should be left to the developer to decide. So yes in your implementation I do think that Backed Enum should not be treated differently than others objects and should throw. PS: I would even revert this change or deprecated it for removal in PHP9 (in a separate RFC) Best regards, Ignace

« previous php.internals (#129656) next »