Le lun. 24 févr. 2025 à 14:57, Gina P. Banyard <intern...@gpb.moe> a écrit :

> On Monday, 24 February 2025 at 11:08, Nicolas Grekas <
> nicolas.grekas+...@gmail.com> wrote:
>
> I'm seeing a push to make the classes final. Please don't!
> This would badly break the open/closed principle to me.
>
> When shipping a new class, one ships two things: a behavior and a type.
> The behavior is what some want to close by making the class final. But the
> result is that the type will also be final. And this would lead to a
> situation where people tighly couple their code to one single
> implementation - the internal one.
>
> The situation I'm telling about is when one will accept an argument
> described as
> function (\Uri\WhatWg\Url $url)
>
> If the Url class is final, this signature means only one possible
> implementation can ever be passed: the native one. Composition cannot be
> achieve because there's no type to compose.
>
> Fine-tuning the behavior provided by the RFC is what we might be most
> interested in, but we should not forget that we also ship a type. By making
> the type non-final, we keep things open enough for userland to build on it.
> If not, we're going to end up with a fragmented community: some will
> tightly couple to the native Url implementation, some others will define a
> UriInterface of their own and will compose it with the native
> implementation, all these with non-interoperable base types of course,
> because interop is hard.
>
> By making the classes non-final, there will be one base type to build upon
> for userland.
> (the alternative would be to define native UrlInterface, but that'd
> increase complexity for little to no gain IMHO - althought that'd solve my
> main concern).
>
>
> The open/closed principle does not mean "open to inheritance".
> Just pulling in the Wikipedia definition: [1]
>
> In object-oriented programming, the open–closed principle (OCP) states
> "software entities (classes, modules, functions, etc.) should be open for
> extension, but closed for modification";
>
>
> You can extend a class by using a decorator or the delegation pattern.
>

Yes.
You can strike decoration with a non-final class (and no base interface),
that's my point.



> But most importantly, I would like to focus on the "closed for
> modification" part of the principle.
> Unless we make *all* the methods final, inheritance allows you to modify
> the behaviour of the methods, which is in *opposition* to the principle.
>
> Moreover, if you extend a WhatWg\Uri to behave differently to the WhatWg
> spec, then you do *not* have a WhatWg URI.
> Which means the type becomes meaningless.
>
> Quoting Dijkstra:
>
> The purpose of abstracting is *not* to be vague, but to create a new
> semantic level in which one can be absolutely precise.
>
>
> A concrete WhatWg\Uri type is abstracting over a raw string.
> And it creates a new semantic level where when you are in possession of
> such a type,
> you _know_ with *absolute* certainty how it behaves and what you can do
> with it, and know that if a consumer needs a WhatWg URI it will not reject
> it.
> This also means consumers of said WhatWg\Uri type do not need to care
> about validation of it.
>
> If one is able to extend a WhatWg URI, then none of the above applies,
> and you just have a raw string with fancy methods.
> I.e. you are now vague, and any consumer of the type needs to do
> validation because it ***cannot*** trust the type, and you have created a
> useless abstraction.
>

A couple of non-final Url classes would still be absolutely useful: e.g. as
a consumer/callee, I would have stated very clearly that I need an object
that behaves like native Url objects. Then, if the implementation doesn't,
that's on the caller. The abstraction would do its job. I don't think the
extra guarantees you're describing would be useful in practice (but you
could still do an exact ::class comparison if you'd really want to).



> It also seems you did not read the relevant "Why a common URI interface
> is not supported?" [2] section of the RFC.
>

This sentence comes to me as unnecessarily confrontational. I’d really like
to keep this discussion as constructive as possible so that php-internal
remains a welcoming space for everyone.


> The major reason why this RFC has had so many iterations and been in
> discussion for so long is because Máté tried, again and again, to have a
> common interface.
> But this just does not make any sense, you cannot make something extremely
> concrete vague and abstract, unless you want to lose all the benefits of
> the abstraction.
>

I was considering the alternative of providing TWO interfaces indeed. Sorry
if that wasn't clear enough.

Nicolas

Reply via email to