Hi Tim,

Thanks for your feedback!


> The RFC is not listed in the overview page: https://wiki.php.net/rfc


Uh, indeed! I've just fixed it.


> 2.
>
> I agree with Dennis' remark that the `Rfc3986Uri` and `WhatWgUri`
> classes must be final. The RFC makes the argument that:
>
> > Having separate classes for the two standards makes it possible to
> > indicate explicit intent at the type level that one specific standard
> > is required.
>
> Developers extending the classes could accidentally violate the
> respective standard, which nullifies the benefit of making invalid
> states unrepresentable at the type-level.
>

On the one hand, I also have some concerns about making these classes final
or non-final
as you probably saw in my last email (the concern came up with a question
about an implementation
detail: https://github.com/php/php-src/pull/14461#discussion_r1847316607).
On the other hand though,
if someone overrides an URI implementation, then I assume there's
definitely a purpose for doing
so (i.e. the child class has additional capabilities, or it can handle
additional protocols). If developers cannot
achieve this via inheritance, then they will do so otherwise (by using
composition, or putting the custom logic
in a helper class etc.). It's just not realistic to prevent logical bugs by
making classes final.

I would rather ask whether it's possible to make the 2 built-in URI
implementations having
quite some special internal behavior behave consistently with userland
classes, even if they are overridden?
For now, the answer seems to be yes (especially after hearing Niels'
solution in the GitHub thread linked above),
but of course new issues may arise later which we don't know about yet. And
of course, it's much easier to make
a class final first and relax the inheritance rules later, than the other
way around... So these are the only reasons
why I'd make the classes final, but otherwise it would be useful to be able
to extend them.

>
> This also means that the return type of the “withers” should be `self`
> instead of `static`, which also means that the “withers” in the
> interface must be `self`. Perhaps this means that they should not exist
> on the interface at all. `DateTimeInterface` only provides the getters,
> likely for a similar reason.
>

Using the `self` return type over `static` would be counterproductive
in my opinion:
it's mostly because static is the correct type semantically, and it can be
useful for
forward compatibility later if we once want to remove the final modifier.

Regarding the analogy with DateTimeInterface, I think this one is wrong:
the ext/uri API is
completely immutable, while ext/date has the mutable DateTime
implementation,
so it's not possible to include setters in the interface, otherwise one
couldn't know
what to expect after modification.

I believe the `UriException` class as the base exception should not be
> `abstract`. There is no real benefit to it, especially since it doesn't
> specify any additional abstract methods.
>

I have no hard feelings regarding this. If I make it a concrete class, then
likely
implementations will start to throw it instead of more specific subclasses.
That's
probably not an issue, people are not usually interested in the exact
reason of an exception.
Since ext/date also added a generic parent exception (DateError) recently
which wasn't abstract,
then I'm fine with doing the same with ext/uri.


> I'm not sure I like the `Interface` suffix on the `UriInterface`
> interface. Just `Uri\Uri` would be equally expressive.
>

Yes, I was expecting this debate :) To be honest, I never liked interfaces
without an "Interface"
suffix, and my dislike didn't go away when I had to use such an interface
somewhere, because it
was difficult for me to find out what the symbol I was typing actually
referred to. But apart from my personal
experiences, I prefer to stay with "UriInterface" because the 2 most well
known internal PHP interfaces
also have the same suffix (DateTimeInterface, SessionInterface), and this
name definitely conveys that
people should not try to instantiate it.

I am not sure about the `*User()` and `*Password()` methods existing on
> the interface. As the RFC acknowledges, RFC 3986 only specifies a
> “userinfo” segment. Should the `*User()` and `*Password()` methods
> perhaps be specific to the `WhatWgUri` class?
>

Really good question, and I hesitated a lot about the same (even in some of
my messages to the mailing list).
In fact, RFC 3986 has some notion of user/password, because the specification
mentions the "user:password"
format as deprecated [in favor of passing authentication information in
other places]. So I think the `*User()` and
`*Password()` methods are legitimately part of the interface. And it's not
even without precedent to have them in
an interface: PSR-7 made use of the "user" and "password" notions in the
`UriInterface::withUserInfo()` method
which accepts a `$user` and a `$password` parameter. I know people on this
list generally don't like PSR-7,
but t would be useful to know why PHP FIG chose to use these two parameters.

Due to the reasons above, the question for me is really whether we want to
add the `*UserInfo()` methods to the
interface or at least to Uri/Rfc3986Uri. Since WhatWg doesn't even mention
user info (apart from "userinfo
percent-encode set" which refers to something else), I'd prefer not to add
the methods in question to Uri/UriInterface.
If people insist on it, then I'm fine to add the methods to Uri\Rfc3986Uri
though.

I disagree with this change and believe that with the current
> capabilities of PHP the out-parameter is the correct API design choice,
> because then the “failure” case would be returning a falsy value, which
> IMO is pretty idiomatic PHP:


Yes, I can live with any of the solutions, I'm just not sure which is less
bad. :) If only we had out parameters... But wishful
thinking aside, I am fine with whatever the majority of people prefer.
Probably being able to unify the API of the two
implementations is a good argument no one thought about so far for using
passing by reference...

Regards,
Máté

Reply via email to