Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:126615 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 061021A00BC for ; Thu, 6 Mar 2025 23:48:33 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1741304757; bh=HmSpOUe+HeqEHBV7kRsIeDrfyEVeX0Cqtf4wxbUSwWQ=; h=Date:From:To:In-Reply-To:References:Subject:From; b=NuLp2O7RDFE+TIgBFjwv/Y5M6Qib1BPdqFRitaGtoTr/hXdHZ/X0x3WMu3mrBDKCD MQFxGL6/fmcwksuBxM3CjgqKPyr7A0Cwnpyl8Nnijybia3Jp2VKhcqfnBGv+w//O7x xRAQDo3kBaQi7zG006Ugi4Jt4Py/2R7k+ROKEs11BT+MCk7U/16XsnckizP59peTgF BB2T5FQTUck8k3yI+0At9GbO5kUyDXBVFeE5eHe6wpkazQHV3n/jYxlsThtieC2dAd xfbE90dmKCJKF9BYRkwhIFWscDbpcJDPCIDpGzvK7ZWSpMIx3WiWC0ONPL/nHnaOSl Jjg9w/lUXPK1Q== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 3E0AE180712 for ; Thu, 6 Mar 2025 23:45:56 +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.8 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_MISSING,HTML_MESSAGE, RCVD_IN_DNSWL_LOW,SPF_HELO_PASS,SPF_PASS autolearn=no autolearn_force=no version=4.0.0 X-Spam-Virus: No X-Envelope-From: Received: from fhigh-b2-smtp.messagingengine.com (fhigh-b2-smtp.messagingengine.com [202.12.124.153]) (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 ; Thu, 6 Mar 2025 23:45:55 +0000 (UTC) Received: from phl-compute-11.internal (phl-compute-11.phl.internal [10.202.2.51]) by mailfhigh.stl.internal (Postfix) with ESMTP id 09175254018D for ; Thu, 6 Mar 2025 18:48:31 -0500 (EST) Received: from phl-imap-09 ([10.202.2.99]) by phl-compute-11.internal (MEProxy); Thu, 06 Mar 2025 18:48:31 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bottled.codes; h=cc:content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm2; t=1741304910; x=1741391310; bh=WLX+Xa4Smm P+RKLO4Y7VxV++Zo+yhe9RlQPcsbAFqU0=; b=dyurRfgmy2FbdcP2rfKRf1paEo skA6wBx4H2rO9vUTqtmpT8Z/kG3MQaQNtGQuXguvLJMRlVjeTG0imRNLCXh740Hj XN42hMRiMwzI017mme8uZAqKl26/3vbijIlaJNLFK2DW5kwuXqLntu47weVz2bzS kfGNhTa/AdzKW7p1bQe+S+GKGyYKoXHHOhgtSGLR/sRFr00O2FUMkKmYmlhYhDT6 zbIcDWZ9xNBN4zWKeyVdoH+ulaK06U3j4gGkPtetNHAqYVaFE8Fk9aBVaBXZ984t zyJVUfEYv9jSNA+Aktce7NK2ZsdYvU/iy2KFzD5FKArt8tWriaWl1LU5vEWw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t= 1741304910; x=1741391310; bh=WLX+Xa4SmmP+RKLO4Y7VxV++Zo+yhe9RlQP csbAFqU0=; b=VnjfB5aeLXf92OcbqSJCFGq20hswhJMZFuX0/xoAV5QBZzp6t0b Rku7+OVxBaOHZEKbTFvS073vfxpFT8uBlaV/EznKRqmAprZ7v8ALmBnSpciffuBf GOL55tLSYSL7Q1kct2G/7godZIcPigDVBx9yPLpqnknWjj+1oDmE1AFsZjW1PAu+ jYWOVKHFdDbVEHPhcr73tCr3C6X/xw1kd47ZTUt3aDxbL5MlkVVWK1wPVotyjOwT u+3A1eIV6TpgMTKzkNridOPYxJPoElHSrbRVJVAsdNvcX04/+NGTtKeAWS/JELd6 UtaGxTSrMS6pYkcTEXD3qZz8jXXmHQEEk1A== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefvddrtddtgddutdeluddvucetufdoteggodetrf dotffvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdggtfgfnhhsuhgsshgtrhhisggv pdfurfetoffkrfgpnffqhgenuceurghilhhouhhtmecufedttdenucenucfjughrpefogg ffhffvkfgjfhfutgesrgdtreerredtjeenucfhrhhomhepfdftohgsucfnrghnuggvrhhs fdcuoehrohgssegsohhtthhlvggurdgtohguvghsqeenucggtffrrghtthgvrhhnpeelke ehtdfgfefhleeilefggeeihfekvdelfeejtdfflefhheehfffgudetuddutdenucffohhm rghinhepphhhphdrnhgvthenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmh grihhlfhhrohhmpehrohgssegsohhtthhlvggurdgtohguvghspdhnsggprhgtphhtthho pedupdhmohguvgepshhmthhpohhuthdprhgtphhtthhopehinhhtvghrnhgrlhhssehlih hsthhsrdhphhhprdhnvght X-ME-Proxy: Feedback-ID: ifab94697:Fastmail Received: by mailuser.phl.internal (Postfix, from userid 501) id 82D98780068; Thu, 6 Mar 2025 18:48:30 -0500 (EST) X-Mailer: MessagingEngine.com Webmail Interface Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net x-ms-reactions: disallow MIME-Version: 1.0 Date: Fri, 07 Mar 2025 00:48:06 +0100 To: internals@lists.php.net Message-ID: In-Reply-To: References: Subject: Re: [PHP-DEV] RFC: short and inner classes Content-Type: multipart/alternative; boundary=acc889e72acf4c56805f9c9c2bf82575 From: rob@bottled.codes ("Rob Landers") --acc889e72acf4c56805f9c9c2bf82575 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable On Thu, Mar 6, 2025, at 23:20, Ilija Tovilo wrote: > Hi Rob >=20 > On Thu, Mar 6, 2025 at 12:14=E2=80=AFAM Rob Landers wrote: > > > > I'd like to introduce my RFC for discussion: https://wiki.php.net/rf= c/short-and-inner-classes >=20 > Thank you for your proposal. >=20 > I'm very much against the idea of introducing yet another slightly > shorter form to declare a class. In your examples (they have been > removed in the meantime), it's unclear how the syntax interacts with > inherited constructors, trait-used constructors, whether repetition of > readonly parent properties leads to a "Cannot modify readonly > property" error, etc. >=20 > The concept of visibility for classes does seem useful to me. Some > questions that crossed my mind when reading the proposal: >=20 > > Inner classes may only be nested one level deep, may not be a parent= class, and may not be declared abstract >=20 > These restrictions seem somewhat arbitrary. For example, you may want > a private class to extend another private class, creating some local > class hierarchy. I think there's value in relaxing this restriction, > if technically possible. They're not 100% arbitrary, but mostly due to technical limitations. - One level deep: Nesting multiple levels results in ambiguous grammar. - As a parent class: This also results in ambiguity. - Abstract: If it cannot be a parent class, it doesn't make sense for it= to be abstract. >=20 > > PHP Fatal error: Private inner class Box::Point cannot be used in t= he global scope >=20 > How is this implemented? I presume using a public nested class as type > hints should be allowed, but these classes may not be loaded when the > function is declared. We implement delayed variance checks for > methods, which do trigger the autoloader, but functions do not (since > they cannot violate variance rules). This happens at run time, when the function is called. I believe we can = guarantee that it will pass/fail with one of the following cases: - The type check passes and everything is fine - The type check fails (due to not being the correct type); autoloading = never happens - The type check succeeds, but it is private/protected; to have an objec= t of that type, you'd have to have loaded the outer class. This is no different than having: function foo(MadeUpClass $c) {} and then never calling foo. >=20 > > Visibility Rules: Private and protected inner classes are only insta= ntiable within their outer class (or subclasses for protected) and canno= t be used as type declarations outside their outer class. This encapsula= tion ensures that the inner class=E2=80=99s implementation details remai= n within their intended scope. >=20 > This introduces a weird case where methods with parameter or return > types referring to private classes may not be redeclared in their > subclasses, given that the type cannot be specified, even if the > methods themselves are not private or final. You do mention something > very similar in your e-mail with the __constructor case, but I really > fail to see how this provides any benefit. Yes. This is correct and inline with other languages with inner types. T= he idea behind it is to encapsulate behavior and hide information. The i= dea is that external code should not know anything about the internal st= ructure. This grants control over inheritance, which you pointed out, th= ough it is better to use final to do that. However, it could be useful i= f you wanted to create a class meant to be inherited (such as a url pars= er) but prevent modification to important methods via inheritance. >=20 > I would also like to echo what has been said about the :: operator, > which feels out of place. I understand that \ comes with additional > autoloading challenges, namely requiring a fallback autoloading > strategy that currently does not conform to PSR-4. It felt natural to me at the time, but I suspect there may be a better n= omenclature; we just need to discover it. >=20 > Disclaimer: I have not looked at the implementation at all yet. >=20 > Ilija >=20 =E2=80=94 Rob --acc889e72acf4c56805f9c9c2bf82575 Content-Type: text/html; charset=utf-8 Content-Transfer-Encoding: quoted-printable

=
On Thu, Mar 6, 2025, at 23:20, Ilija Tovilo wrote:
Hi Rob
<= div>
On Thu, Mar 6, 2025 at 12:14=E2=80=AFAM Rob Landers &= lt;rob@bottled.codes> wrote:=
>
> I'd like to introduce my RFC for = discussion: https://wiki.php.net/rfc/short-and-inner-classes

Thank you for your proposal.

I'm very much against the idea of introducing yet another slightly
=
shorter form to declare a class. In your examples (they have = been
removed in the meantime), it's unclear how the syntax= interacts with
inherited constructors, trait-used constru= ctors, whether repetition of
readonly parent properties le= ads to a "Cannot modify readonly
property" error, etc.
=

The concept of visibility for classes does see= m useful to me. Some
questions that crossed my mind when r= eading the proposal:

> Inner classes may= only be nested one level deep, may not be a parent class, and may not b= e declared abstract

These restrictions seem= somewhat arbitrary. For example, you may want
a private c= lass to extend another private class, creating some local
= class hierarchy. I think there's value in relaxing this restriction,
=
if technically possible.

They're not 100% arbitrary, but mostly due to technical limitation= s.

- One level deep: Nesting multiple level= s results in ambiguous grammar.
- As a parent class: This = also results in ambiguity.
- Abstract: If it cannot be a p= arent class, it doesn't make sense for it to be abstract.
=

=
> PHP Fatal error:  Private inner class Box::Point cannot b= e used in the global scope

How is this impl= emented? I presume using a public nested class as type
hin= ts should be allowed, but these classes may not be loaded when the
function is declared. We implement delayed variance checks for<= br>
methods, which do trigger the autoloader, but functions do= not (since
they cannot violate variance rules).
=

This happens at run time, when the func= tion is called. I believe we can guarantee that it will pass/fail with o= ne of the following cases:

- The type check= passes and everything is fine
- The type check fails (due= to not being the correct type); autoloading never happens
- The type check succeeds, but it is private/protected; to have an obje= ct of that type, you'd have to have loaded the outer class.

This is no different than having:

function foo(MadeUpClass $c) {}

and= then never calling foo.


> Visibility Rules: Private a= nd protected inner classes are only instantiable within their outer clas= s (or subclasses for protected) and cannot be used as type declarations = outside their outer class. This encapsulation ensures that the inner cla= ss=E2=80=99s implementation details remain within their intended scope.<= br>

This introduces a weird case where methods = with parameter or return
types referring to private classe= s may not be redeclared in their
subclasses, given that th= e type cannot be specified, even if the
methods themselves= are not private or final. You do mention something
very s= imilar in your e-mail with the __constructor case, but I really
fail to see how this provides any benefit.
<= div>
Yes. This is correct and inline with other languages = with inner types. The idea behind it is to encapsulate behavior and hide= information. The idea is that external code should not know anything ab= out the internal structure. This grants control over inheritance, which = you pointed out, though it is better to use final to do that. However, i= t could be useful if you wanted to create a class meant to be inherited = (such as a url parser) but prevent modification to important methods via= inheritance.


I would also like to echo what has been= said about the :: operator,
which feels out of place. I u= nderstand that \ comes with additional
autoloading challen= ges, namely requiring a fallback autoloading
strategy that= currently does not conform to PSR-4.

It felt natural to me at the time, but I suspect there may be a = better nomenclature; we just need to discover it.


Disclai= mer: I have not looked at the implementation at all yet.
<= br>
Ilija


=
=E2=80=94 Rob
--acc889e72acf4c56805f9c9c2bf82575--