Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:126491 X-Original-To: internals@lists.php.net Delivered-To: internals@lists.php.net Received: from php-smtp4.php.net (php-smtp4.php.net [45.112.84.5]) by qa.php.net (Postfix) with ESMTPS id 9DC2F1A00BC for ; Mon, 24 Feb 2025 13:45:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1740404550; bh=btvjF+Gub2aQwgqYrEl5KqkW7n1Hq0S1tOcJrf06WEM=; h=References:In-Reply-To:From:Date:Subject:To:Cc:From; b=PnrsBNb00lUpPBCHtTVkvN5bjulFUrpTZPVPDa+YcMEOx7vUY+//pldv/4LM7K4P5 723nU51KRtyVB0QIE5b4Z6rJi6U0yVDPOW3yEHBCQFwJjZqbY4f9QjUH0CF0CBY1Yk ZcDeqLNsTME5ZjqSrPMBDyg2tSzK6BL24/gVH+yZor9skqdhfoIJFEa6veNVWnzSEx zLelkMMRBw5knyYIljA9xtdKgWsJik0kl5ozbBddADILbxsZ2psb4khvr4eqcdv2vj UctEDIZrme9eFxmdXX4bCdbQCZ5qocRQbQtUpjqlHvhqnO8ltI2+tyqggjP2xiAJZr g/BrBMY9rOFXQ== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 92FA91801DA for ; Mon, 24 Feb 2025 13:42:29 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.0 (2022-12-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_40,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS,FREEMAIL_FROM, HTML_MESSAGE,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE, SPF_PASS autolearn=no autolearn_force=no version=4.0.0 X-Spam-Virus: No X-Envelope-From: Received: from mail-lf1-f44.google.com (mail-lf1-f44.google.com [209.85.167.44]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Mon, 24 Feb 2025 13:42:29 +0000 (UTC) Received: by mail-lf1-f44.google.com with SMTP id 2adb3069b0e04-54838cd334cso3340819e87.1 for ; Mon, 24 Feb 2025 05:45:08 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1740404707; x=1741009507; darn=lists.php.net; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=/LgK+GRU60vLgN/hPLTJatVbgpKoccYGoR0EEOD2nu4=; b=DGQhDFWmG6FE2teBnn06+kph7j+TPP0HJ6nXc9SjNvcOTGc2xjsM63E4Fvu7mKiu4L x/dm5RvrQTMtRGTIxgrWJ+6psKWcolSat8kfUiB0v13szfLlio/fRuZvo5VgYOrOJE4T rvLD2TjNPaFwWaqXcSYsuQjXQji0jbpuTj7C8QbBK2lHsd+6PXF9S8eT1aLDLxg6Ipga LhUk9QYEHr5KkpCTNfxOG09AVPHYR07eR+Fi2xvgWbIBP+9YZHcUqC3JHQT3aaLZuEcz Qf4i77hWHt2WRvYGr2chq+5+uKNY0HDowo5yccR2gyxjHjkL8u8bhOiCRPv0VP/IjYAQ D6Kg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1740404707; x=1741009507; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=/LgK+GRU60vLgN/hPLTJatVbgpKoccYGoR0EEOD2nu4=; b=ilmkPooTmNW2GwRkLjPXszkFuclHPF0gjw01kwexrWSDmZCJR0sBF0/UK4xaWv2fJB iv0nbvp2U4dOsxLC/AVAwLCisZ8Rjwc+hMkIgItxQrUly954eba14gFmjsVSDzewb+AQ 6nDkDTdizApg+qixYjAwFbMN2oEtVqWf8rMMd9db1GbOnW3KgUwQqITFsXXQBjcPrUAV ITfyvuNZx3ViMW3MivH/nc7wCpTsqDo8Ujoesx/Lw8hmdQZhEBbAfdpqmb9t3d9KMo8v 9YDi0DunY2SOVFXbyHNEv/LUwph+XFU2DgE54EsJyZdSLSHaXlrsMBF+2phvQPwGX/om drPg== X-Gm-Message-State: AOJu0YysHWeezejnwja7Gdyzxp4eZbjzWpcsxU+XbB1cbGEu+PdVx8nL ZZEtQQktdkVutcdlMa/r20+h2J+xgC/ftp1I+XokAHGxPgCrMxIMxoL5WIFvprTw0cviJz+Sn/D ylQqYXjL9J5wxQWLbemzJ3dlhdrQ= X-Gm-Gg: ASbGncuJyLUX+0sm6Ml6bN6ASC4BDT65tDiukravFZ9Z794Dyg+0FHTeN4oKN2vQzvy kT9F+QGBn3/97OVJ44nnExeBLyiP9yM2GXL6RkovIKszmRXncw0f+/3vxgPB59h3SqacJtxd/aD dK8/+92A== X-Google-Smtp-Source: AGHT+IHwTnickGcfNYo4A/MoX5y6zfglIgxsq93Peox9LFqSAwTaDFSVe0wrSmXY7qpUmHfPbsESQIXOdWm57efETL4= X-Received: by 2002:a05:6512:2827:b0:545:5d:a5e8 with SMTP id 2adb3069b0e04-54838eddecamr4047992e87.9.1740404706042; Mon, 24 Feb 2025 05:45:06 -0800 (PST) Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net x-ms-reactions: disallow MIME-Version: 1.0 References: <1BCB4144-231D-45EA-A914-98EE8F0F503A@automattic.com> <8E614C9C-BA85-45D8-9A4E-A30D69981C5D@automattic.com> <9bf11a89-39d9-457b-b0ea-789fd07d7370@gmail.com> <804ddb57fee36c23839c5b5a50ddd51f@bastelstu.be> In-Reply-To: <804ddb57fee36c23839c5b5a50ddd51f@bastelstu.be> Date: Mon, 24 Feb 2025 14:44:53 +0100 X-Gm-Features: AWEUYZkkePa-uUDts6sPw8LxNwddh58zVkUiaL1cyD-VDNBY7ohJjx0Ta-FXaU4 Message-ID: Subject: Re: [PHP-DEV] [RFC] [Discussion] Add WHATWG compliant URL parsing API To: =?UTF-8?Q?Tim_D=C3=BCsterhus?= Cc: internals@lists.php.net Content-Type: multipart/alternative; boundary="00000000000044e95a062ee38cbf" From: nicolas.grekas+php@gmail.com (Nicolas Grekas) --00000000000044e95a062ee38cbf Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Am 2025-02-24 12:08, schrieb Nicolas Grekas: > > 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. > > Yes, that's the point: The behavior and the type are intimately tied > together. The Uri/Url classes are representing values, not services. You > wouldn't extend an int either. For DateTimeImmutable inheritance being > legal causes a ton of needless bugs (especially around serialization > behavior). > DatetimeImmutable is a good example of community-proven usefulness for inheritance: the carbon package has a huge success because it does add a ton of nice helpers (that are better maintained in userland) while still providing compatibility with functions that accept the native type. The fact that the native implementation had bugs when inheritance was used doesn't mean inheritance is a problem. It's just bugs that need to be fixed. Conceptually nothing makes those bugs inevitable. Closing the class would have hindered community-innovation. The same applies here. Then, if people make mistakes in their child classes, their problem. But the community shouldn't be forbidden to extend a class just because mistakes can happen. > > 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 > > For a given specification (RFC 3986 / WHATWG) there is exactly one > correct interpretation of a given URL. =E2=80=9CFine-tuning=E2=80=9D mean= s that you are > no longer following the specification. > See Carbon example, it's not specifically about fine-tuning. We cannot anticipate how creative people are. Nor should we prevent them from being so, from the PoV of the PHP engine designers. > the type non-final, we keep things open enough for userland to build on > > it. > > This works: > > final class HttpUrl { > private readonly \Uri\Rfc3986\Uri $uri; > public function __construct(string $uri) { > $this->uri =3D new \Uri\Rfc3986\Uri($uri); > if ($this->uri->getScheme() !=3D=3D 'http') { > throw new ValueError('Scheme must be http'); > } > } > public function toRfc3986(): \Uri\Rfc3986\Uri { > return $this->uri; > } > } > > Userland can easily build their convenience wrappers around the classes, > they just need to export them to the native classes which will then > guarantee that the result is fully validated and actually a valid > URI/URL. Keep in mind that the ext/uri extension will always be > available, thus users can rely on the native implementation. > This is an example of what I call community-fragmentation: one hardcoded type that should only be used as an implementation detail, but will leak at type-boundaries and will make things inflexible. Each project will have to think about such designs, and many more will get it wrong. (We will be the ones to blame since we're the ones educated on the topic.) > > 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). > > Mate already explained why a native UriInterface was intentionally > removed from the RFC in https://news-web.php.net/php.internals/126425. > The only one option remains - making the class non-final. Nicolas --00000000000044e95a062ee38cbf Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable


Am = 2025-02-24 12:08, schrieb Nicolas Grekas:
> The situation I'm telling about is when one will accept an argumen= t
> 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.

Yes, that's the point: The behavior and the type are intimately tied together. The Uri/Url classes are representing values, not services. You wouldn't extend an int either. For DateTimeImmutable inheritance being =
legal causes a ton of needless bugs (especially around serialization
behavior).

DatetimeImmutable is a good = example of community-proven usefulness=C2=A0for inheritance:
the = carbon package has a huge success because it does add a ton of nice helpers= (that are better maintained in userland) while still providing compatibili= ty with functions that accept the native type.

The= fact that the native implementation had bugs when inheritance was used doe= sn't mean inheritance is a problem. It's just bugs that need to be = fixed. Conceptually nothing makes those bugs inevitable.=C2=A0
Closing the class would have hindered community-innovation. Th= e same applies here.

Then, if people make mistakes= in their child classes, their problem. But the community shouldn't be = forbidden to extend a class just because mistakes can happen.
=C2= =A0
> Fine-tuning the behavior provided by the RFC is what we might be most<= br> > interested in, but we should not forget that we also ship a type. By <= br> > making

For a given specification (RFC 3986 / WHATWG) there is exactly one
correct interpretation of a given URL. =E2=80=9CFine-tuning=E2=80=9D means = that you are
no longer following the specification.

= See Carbon example, it's not specifically about fine-tuning. We cannot = anticipate how creative people are. Nor should we prevent them from being s= o, from the PoV of the PHP engine designers.


<= /div>
> the type non-fi= nal, we keep things open enough for userland to build on
> it.

This works:

=C2=A0 =C2=A0 =C2=A0final class HttpUrl {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0private readonly \Uri\Rfc3986\Uri $uri; =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0public function __construct(string $uri) = {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0$this->uri =3D new \Uri\= Rfc3986\Uri($uri);
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if ($this->uri->getSc= heme() !=3D=3D 'http') {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0throw new Val= ueError('Scheme must be http');
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0}
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0}
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0public function toRfc3986(): \Uri\Rfc3986= \Uri {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return $this->uri;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0}
=C2=A0 =C2=A0 =C2=A0}

Userland can easily build their convenience wrappers around the classes, they just need to export them to the native classes which will then
guarantee that the result is fully validated and actually a valid
URI/URL. Keep in mind that the ext/uri extension will always be
available, thus users can rely on the native implementation.

This is an example of what I call community-fragmenta= tion: one hardcoded type that should only be used as an implementation deta= il, but will leak at type-boundaries and will make things inflexible. Each = project will have to think about such designs, and many more will get it wr= ong. (We will be the ones to blame since we're the ones educated on the= topic.)

=C2=A0
> 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).

Mate already explained why a native UriInterface was intentionally
removed from the RFC in https://news-web.php.net/php.in= ternals/126425.

The only one option= remains - making the class non-final.

Nicolas=
--00000000000044e95a062ee38cbf--